From b9106b0ecdb712ecae9b0030c0f2c3f14803fa8d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 2 Apr 2010 13:19:02 -0700 Subject: [PATCH 01/73] Use AF_INET sockets instead of always AF_INET6 You can get AF_INET6 still, it's just not the only choice. --- lib/net.js | 69 +++++++------ src/node_net2.cc | 163 +++++++++++++++---------------- test/pummel/test-tcp-pingpong.js | 6 +- 3 files changed, 122 insertions(+), 116 deletions(-) diff --git a/lib/net.js b/lib/net.js index dd415f7d23f..d4926c64710 100644 --- a/lib/net.js +++ b/lib/net.js @@ -39,7 +39,7 @@ var setNoDelay = binding.setNoDelay; var socketError = binding.socketError; var getsockname = binding.getsockname; var getaddrinfo = binding.getaddrinfo; -var needsLookup = binding.needsLookup; +var isIP = binding.isIP; var errnoException = binding.errnoException; var EINPROGRESS = binding.EINPROGRESS; var ENOENT = binding.ENOENT; @@ -422,6 +422,7 @@ Stream.prototype.write = function (data, encoding) { Stream.prototype._writeOut = function (data, encoding) { if (!this.writable) throw new Error('Stream is not writable'); + if (data.length == 0) return true; var buffer, off, len; var bytesWritten, charsWritten; @@ -566,6 +567,8 @@ function doConnect (socket, port, host) { return; } + debug('connecting to ' + host + ' : ' + port); + // Don't start the read watcher until connection is established socket._readWatcher.set(socket.fd, true, false); @@ -607,13 +610,13 @@ Stream.prototype.connect = function () { var port = parseInt(arguments[0]); if (port >= 0) { - self.fd = socket('tcp'); //debug('new fd = ' + self.fd); - self.type = 'tcp'; // TODO dns resolution on arguments[1] var port = arguments[0]; self._resolving = true; - lookupDomainName(arguments[1], function (ip) { + lookupDomainName(arguments[1], function (ip, isV4) { + self.type = isV4 ? 'tcp4' : 'tcp6'; + self.fd = socket(self.type); self._resolving = false; doConnect(self, port, ip); }); @@ -729,8 +732,8 @@ function Server (listener) { if (!peerInfo) return; var s = new Stream(peerInfo.fd); - s.remoteAddress = peerInfo.remoteAddress; - s.remotePort = peerInfo.remotePort; + s.remoteAddress = peerInfo.address; + s.remotePort = peerInfo.port; s.type = self.type; s.server = self; s.resume(); @@ -750,25 +753,27 @@ exports.createServer = function (listener) { return new Server(listener); }; -/* This function does both an ipv4 and ipv6 look up. - * It first tries the ipv4 look up, if that fails, then it does the ipv6. - */ +// This function does both an ipv4 and ipv6 look up. +// It first tries the ipv4 look up, if that fails, then it does the ipv6. +// callback(dn, isV4 function lookupDomainName (dn, callback) { - if (!needsLookup(dn)) { + var kind = isIP(dn); + debug('kind = ' + kind); + if (kind) { // Always wait until the next tick this is so people can do // // server.listen(8000); // server.addListener('listening', fn); // // Marginally slower, but a lot fewer WTFs. - process.nextTick(function () { callback(dn); }) + process.nextTick(function () { callback(dn, kind == 4 ? true : false); }) } else { debug("getaddrinfo 4 " + dn); getaddrinfo(dn, 4, function (r4) { if (r4 instanceof Error) throw r4; if (r4.length > 0) { debug("getaddrinfo 4 found " + r4); - callback(r4[0]); + callback(r4[0], true); } else { debug("getaddrinfo 6 " + dn); getaddrinfo(dn, 6, function (r6) { @@ -777,7 +782,7 @@ function lookupDomainName (dn, callback) { throw new Error("No address associated with hostname " + dn); } debug("getaddrinfo 6 found " + r6); - callback(r6[0]); + callback(r6[0], false); }); } }); @@ -797,13 +802,6 @@ Server.prototype.listen = function () { var self = this; if (self.fd) throw new Error('Server already opened'); - function doListen () { - listen(self.fd, 128); - self.watcher.set(self.fd, true, false); - self.watcher.start(); - self.emit("listening"); - } - if (typeof(arguments[0]) == 'string') { // the first argument specifies a path self.fd = socket('unix'); @@ -815,7 +813,7 @@ Server.prototype.listen = function () { if (err) { if (err.errno == ENOENT) { bind(self.fd, path); - doListen(); + self._doListen(); } else { throw r; } @@ -828,30 +826,41 @@ Server.prototype.listen = function () { throw err; } else { bind(self.fd, path); - doListen(); + self._doListen(); } }); } } }); - } else if (!arguments[0]) { + } else if (!arguments[1]) { // Don't bind(). OS will assign a port with INADDR_ANY. // The port can be found with server.address() - self.fd = socket('tcp'); - self.type = 'tcp'; - doListen(); + self.type = 'tcp4'; + self.fd = socket(self.type); + bind(self.fd, arguments[0]); + process.nextTick(function () { + self._doListen(); + }); } else { // the first argument is the port, the second an IP - self.fd = socket('tcp'); - self.type = 'tcp'; var port = arguments[0]; - lookupDomainName(arguments[1], function (ip) { + lookupDomainName(arguments[1], function (ip, isV4) { + self.type = isV4 ? 'tcp4' : 'tcp6'; + self.fd = socket(self.type); bind(self.fd, port, ip); - doListen(); + self._doListen(); }); } }; +Server.prototype._doListen = function () { + listen(this.fd, 128); + this.watcher.set(this.fd, true, false); + this.watcher.start(); + this.emit("listening"); +} + + Server.prototype.address = function () { return getsockname(this.fd); diff --git a/src/node_net2.cc b/src/node_net2.cc index 2ddeb51ada3..de32dc419fd 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -38,8 +38,6 @@ static Persistent errno_symbol; static Persistent syscall_symbol; static Persistent fd_symbol; -static Persistent remote_address_symbol; -static Persistent remote_port_symbol; static Persistent address_symbol; static Persistent port_symbol; static Persistent type_symbol; @@ -467,20 +465,27 @@ static Handle Socket(const Arguments& args) { HandleScope scope; // default to TCP - int domain = PF_INET6; + int domain = PF_INET; int type = SOCK_STREAM; if (args[0]->IsString()) { String::Utf8Value t(args[0]->ToString()); + // FIXME optimize this cascade. if (0 == strcasecmp(*t, "TCP")) { + domain = PF_INET; + type = SOCK_STREAM; + } else if (0 == strcasecmp(*t, "TCP4")) { + domain = PF_INET; + type = SOCK_STREAM; + } else if (0 == strcasecmp(*t, "TCP6")) { domain = PF_INET6; type = SOCK_STREAM; + } else if (0 == strcasecmp(*t, "UNIX")) { + domain = PF_UNIX; + type = SOCK_STREAM; } else if (0 == strcasecmp(*t, "UDP")) { domain = PF_INET6; type = SOCK_DGRAM; - } else if (0 == strcasecmp(*t, "UNIX")) { - domain = PF_UNIX; - type = SOCK_STREAM; } else { return ThrowException(Exception::Error( String::New("Unknown socket type."))); @@ -505,13 +510,14 @@ static Handle Socket(const Arguments& args) { // (yes this is all to avoid one small heap alloc) static struct sockaddr *addr; static socklen_t addrlen; -static struct sockaddr_un un; -static struct sockaddr_in6 in6; static inline Handle ParseAddressArgs(Handle first, Handle second, - struct in6_addr default_addr - ) { - if (first->IsString() && second->IsUndefined()) { + bool is_bind) { + static struct sockaddr_un un; + static struct sockaddr_in in; + static struct sockaddr_in6 in6; + + if (first->IsString() && !second->IsString()) { // UNIX String::Utf8Value path(first->ToString()); @@ -528,36 +534,32 @@ static inline Handle ParseAddressArgs(Handle first, } else { // TCP or UDP - int port = first->Int32Value(); + memset(&in, 0, sizeof in); memset(&in6, 0, sizeof in6); + + int port = first->Int32Value(); + in.sin_port = in6.sin6_port = htons(port); + in.sin_family = AF_INET; + in6.sin6_family = AF_INET6; + + bool is_ipv4 = true; + if (!second->IsString()) { - in6.sin6_addr = default_addr; + in.sin_addr.s_addr = htonl(is_bind ? INADDR_ANY : INADDR_LOOPBACK); + in6.sin6_addr = is_bind ? in6addr_any : in6addr_loopback; } else { String::Utf8Value ip(second->ToString()); - char ipv6[255] = "::FFFF:"; - - if (inet_pton(AF_INET, *ip, &(in6.sin6_addr)) > 0) { - // If this is an IPv4 address then we need to change it - // to the IPv4-mapped-on-IPv6 format which looks like - // ::FFFF: - // For more information see "Address Format" ipv6(7) and - // "BUGS" in inet_pton(3) - strcat(ipv6, *ip); - } else { - strcpy(ipv6, *ip); - } - - if (inet_pton(AF_INET6, ipv6, &(in6.sin6_addr)) <= 0) { - return ErrnoException(errno, "inet_pton", "Invalid IP Address"); + if (inet_pton(AF_INET, *ip, &(in.sin_addr)) <= 0) { + is_ipv4 = false; + if (inet_pton(AF_INET6, *ip, &(in6.sin6_addr)) <= 0) { + return ErrnoException(errno, "inet_pton", "Invalid IP Address"); + } } } - in6.sin6_family = AF_INET6; - in6.sin6_port = htons(port); - - addr = (struct sockaddr*)&in6; - addrlen = sizeof in6; + addr = is_ipv4 ? (struct sockaddr*)&in : (struct sockaddr*)&in6; + addrlen = is_ipv4 ? sizeof in : sizeof in6; } return Handle(); } @@ -578,7 +580,7 @@ static Handle Bind(const Arguments& args) { FD_ARG(args[0]) - Handle error = ParseAddressArgs(args[1], args[2], in6addr_any); + Handle error = ParseAddressArgs(args[1], args[2], true); if (!error.IsEmpty()) return ThrowException(error); int flags = 1; @@ -658,7 +660,7 @@ static Handle Connect(const Arguments& args) { FD_ARG(args[0]) - Handle error = ParseAddressArgs(args[1], args[2], in6addr_loopback); + Handle error = ParseAddressArgs(args[1], args[2], false); if (!error.IsEmpty()) return ThrowException(error); int r = connect(fd, addr, addrlen); @@ -671,6 +673,31 @@ static Handle Connect(const Arguments& args) { } +#define ADDRESS_TO_JS(info, address_storage) \ +do { \ + char ip[INET6_ADDRSTRLEN]; \ + int port; \ + struct sockaddr_in *a4; \ + struct sockaddr_in6 *a6; \ + switch ((address_storage).ss_family) { \ + case AF_INET6: \ + a6 = (struct sockaddr_in6*)&(address_storage); \ + inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a6->sin6_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + case AF_INET: \ + a4 = (struct sockaddr_in*)&(address_storage); \ + inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \ + port = ntohs(a4->sin_port); \ + (info)->Set(address_symbol, String::New(ip)); \ + (info)->Set(port_symbol, Integer::New(port)); \ + break; \ + } \ +} while (0) + + static Handle GetSockName(const Arguments& args) { HandleScope scope; @@ -687,17 +714,7 @@ static Handle GetSockName(const Arguments& args) { Local info = Object::New(); - if (address_storage.ss_family == AF_INET6) { - struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage; - - char ip[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN); - - int port = ntohs(a->sin6_port); - - info->Set(address_symbol, String::New(ip)); - info->Set(port_symbol, Integer::New(port)); - } + ADDRESS_TO_JS(info, address_storage); return scope.Close(info); } @@ -719,17 +736,7 @@ static Handle GetPeerName(const Arguments& args) { Local info = Object::New(); - if (address_storage.ss_family == AF_INET6) { - struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage; - - char ip[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN); - - int port = ntohs(a->sin6_port); - - info->Set(remote_address_symbol, String::New(ip)); - info->Set(remote_port_symbol, Integer::New(port)); - } + ADDRESS_TO_JS(info, address_storage); return scope.Close(info); } @@ -753,8 +760,8 @@ static Handle Listen(const Arguments& args) { // var peerInfo = t.accept(server_fd); // // peerInfo.fd -// peerInfo.remoteAddress -// peerInfo.remotePort +// peerInfo.address +// peerInfo.port // // Returns a new nonblocking socket fd. If the listen queue is empty the // function returns null (wait for server_fd to become readable and try @@ -784,17 +791,7 @@ static Handle Accept(const Arguments& args) { peer_info->Set(fd_symbol, Integer::New(peer_fd)); - if (address_storage.ss_family == AF_INET6) { - struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage; - - char ip[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN); - - int port = ntohs(a->sin6_port); - - peer_info->Set(remote_address_symbol, String::New(ip)); - peer_info->Set(remote_port_symbol, Integer::New(port)); - } + ADDRESS_TO_JS(peer_info, address_storage); return scope.Close(peer_info); } @@ -1226,28 +1223,28 @@ static Handle GetAddrInfo(const Arguments& args) { } -static Handle NeedsLookup(const Arguments& args) { +static Handle IsIP(const Arguments& args) { HandleScope scope; - - if (args[0]->IsNull() || args[0]->IsUndefined()) return False(); + + if (!args[0]->IsString()) { + return scope.Close(Integer::New(4)); + } String::Utf8Value s(args[0]->ToString()); // avoiding buffer overflows in the following strcat // 2001:0db8:85a3:08d3:1319:8a2e:0370:7334 // 39 = max ipv6 address. - if (s.length() > INET6_ADDRSTRLEN) return True(); + if (s.length() > INET6_ADDRSTRLEN) { + return scope.Close(Integer::New(0)); + } struct sockaddr_in6 a; - if (inet_pton(AF_INET, *s, &(a.sin6_addr)) > 0) return False(); - if (inet_pton(AF_INET6, *s, &(a.sin6_addr)) > 0) return False(); + if (inet_pton(AF_INET, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(4)); + if (inet_pton(AF_INET6, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(6)); - char ipv6[255] = "::FFFF:"; - strcat(ipv6, *s); - if (inet_pton(AF_INET6, ipv6, &(a.sin6_addr)) > 0) return False(); - - return True(); + return scope.Close(Integer::New(0)); } @@ -1291,7 +1288,7 @@ void InitNet2(Handle target) { NODE_SET_METHOD(target, "getsockname", GetSockName); NODE_SET_METHOD(target, "getpeername", GetPeerName); NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo); - NODE_SET_METHOD(target, "needsLookup", NeedsLookup); + NODE_SET_METHOD(target, "isIP", IsIP); NODE_SET_METHOD(target, "errnoException", CreateErrnoException); target->Set(String::NewSymbol("ENOENT"), Integer::New(ENOENT)); @@ -1305,8 +1302,6 @@ void InitNet2(Handle target) { errno_symbol = NODE_PSYMBOL("errno"); syscall_symbol = NODE_PSYMBOL("syscall"); fd_symbol = NODE_PSYMBOL("fd"); - remote_address_symbol = NODE_PSYMBOL("remoteAddress"); - remote_port_symbol = NODE_PSYMBOL("remotePort"); address_symbol = NODE_PSYMBOL("address"); port_symbol = NODE_PSYMBOL("port"); } diff --git a/test/pummel/test-tcp-pingpong.js b/test/pummel/test-tcp-pingpong.js index 73d36c82d9d..c9a66ffc912 100644 --- a/test/pummel/test-tcp-pingpong.js +++ b/test/pummel/test-tcp-pingpong.js @@ -11,10 +11,12 @@ function pingPongTest (port, host, on_complete) { var server = net.createServer(function (socket) { assert.equal(true, socket.remoteAddress !== null); assert.equal(true, socket.remoteAddress !== undefined); - if (host === "127.0.0.1") + if (host === "127.0.0.1" || host === "localhost" || !host) { assert.equal(socket.remoteAddress, "127.0.0.1"); - else if (host == null) + } else { + puts('host = ' + host + ', remoteAddress = ' + socket.remoteAddress); assert.equal(socket.remoteAddress, "::1"); + } socket.setEncoding("utf8"); socket.setNoDelay(); From 53530e981a81e25e527e6e6ee3aeae8b1beaac59 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 2 Apr 2010 14:55:28 -0700 Subject: [PATCH 02/73] Fix test-http-chunked. Need to check for \0 at end of utf8 strings --- lib/http.js | 3 +-- lib/net.js | 21 ++++++++++++--------- src/node.cc | 3 ++- test/simple/test-http-chunked.js | 5 ++++- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/http.js b/lib/http.js index 554f047d4b6..da957eaece4 100644 --- a/lib/http.js +++ b/lib/http.js @@ -707,8 +707,7 @@ exports.cat = function (url, encoding_, headers_) { }); client.addListener("error", function (err) { - // todo an error should actually be passed here... - if (callback) callback(new Error('Connection error')); + if (callback) callback(err); }); req.close(); diff --git a/lib/net.js b/lib/net.js index d4926c64710..191d872c07e 100644 --- a/lib/net.js +++ b/lib/net.js @@ -443,20 +443,23 @@ Stream.prototype._writeOut = function (data, encoding) { allocNewPool(); } - if (encoding == 'utf8' || encoding == 'utf-8') { + if (encoding == 'binary') { + bytesWritten = pool.binaryWrite(data, pool.used); + charsWritten = bytesWritten; + } else if (encoding == 'ascii') { + bytesWritten = pool.asciiWrite(data, pool.used); + charsWritten = bytesWritten; + + } else { + // default to utf8 bytesWritten = pool.utf8Write(data, pool.used); + // Don't include the null + if (pool[pool.used + bytesWritten-1] == 0) bytesWritten--; // XXX Hacky way to find out the number of characters written. // Waiting for a more optimal way: http://codereview.chromium.org/1539013 var _s = pool.utf8Slice(pool.used, pool.used + bytesWritten); charsWritten = _s.length; - } else if (encoding == 'ascii') { - bytesWritten = pool.asciiWrite(data, pool.used); - charsWritten = bytesWritten; - assert(charsWritten <= data.length); - } else { - bytesWritten = pool.binaryWrite(data, pool.used); - charsWritten = bytesWritten; - assert(charsWritten <= data.length); + } assert(bytesWritten > 0); diff --git a/src/node.cc b/src/node.cc index 452c111b11f..4965237024c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -218,7 +218,8 @@ ssize_t DecodeBytes(v8::Handle val, enum encoding encoding) { #endif // Returns number of bytes written. -ssize_t DecodeWrite(char *buf, size_t buflen, +ssize_t DecodeWrite(char *buf, + size_t buflen, v8::Handle val, enum encoding encoding) { HandleScope scope; diff --git a/test/simple/test-http-chunked.js b/test/simple/test-http-chunked.js index a838235472d..a3395fcb9cb 100644 --- a/test/simple/test-http-chunked.js +++ b/test/simple/test-http-chunked.js @@ -1,7 +1,7 @@ require("../common"); var http = require("http"); -var UTF8_STRING = "Il était tué"; +var UTF8_STRING = "南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、经济现状。"; var server = http.createServer(function(req, res) { res.writeHead(200, {"Content-Type": "text/plain; charset=utf8"}); @@ -12,6 +12,9 @@ server.listen(PORT); http.cat("http://127.0.0.1:"+PORT+"/", "utf8", function (err, data) { if (err) throw err; + assert.equal('string', typeof data); + puts('here is the response:'); assert.equal(UTF8_STRING, data); + puts(data); server.close(); }) From 94644d743c0aa04fb2bc9e1267205b02c6ee7f82 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 2 Apr 2010 15:57:32 -0700 Subject: [PATCH 03/73] Remove multipart library Too messy, unmaintainable. Pull it out of the history if you need it. --- doc/api.markdown | 170 -------- lib/multipart.js | 437 --------------------- src/node.cc | 1 - test/fixtures/multipart.js | 721 ---------------------------------- test/pummel/test-multipart.js | 140 ------- 5 files changed, 1469 deletions(-) delete mode 100644 lib/multipart.js delete mode 100644 test/fixtures/multipart.js delete mode 100644 test/pummel/test-multipart.js diff --git a/doc/api.markdown b/doc/api.markdown index 39d625063c2..10f3f5cc773 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1483,176 +1483,6 @@ Resumes a paused response. A reference to the `http.Client` that this response belongs to. -## Multipart Parsing - -A library to parse `multipart` internet messages is included with -Node. To use it, `require("multipart")`. - -### multipart.parse(message) - -Returns a multipart.Stream wrapper around a streaming message. -The message must contain a `headers` member, and may be either an -HTTP request object or a JSGI-style request object with either a -forEachable or String body. - -See the Stream class below. - -### multipart.cat(message, callback) - -On success, `callback` is called with `(null, stream)` where `stream` is a -`multipart.Stream` object representing the completed message. The body of -each part is saved on the `body` member. - -On error, `callback` is called with `(err)` where `err` is an instanceof -the `Error` object. This indicates that the message was malformed in some -way. - -*Note*: This function saves the *entire* message into memory. As such, it -is ill-suited to parsing actual incoming messages from an HTTP request! -If a user uploads a very large file, then it may cause serious problems. -No checking is done to ensure that the file does not overload the memory. -Only use `multipart.cat` with known and trusted input! - - -### multipart.Stream - -The multipart.Stream class is a streaming parser wrapped around a message. -The Stream also contains the properties described for the `part` objects below, and is a reference to the top-level message. - -This is an EventEmitter with the following events: - -- **`"partBegin"`** - `callback(part)`: -Emitted when a new part is found in the stream. `part` is a `part object`, described below. - -- **`"partEnd"`** - `callback(part)`: - Emitted when a part is done. - -- **`"body"`** - `callback(chunk)`: - Emitted when a chunk of the body is read. - -- **`"complete"`** - `callback()`: - Emitted when the end of the stream is reached. - -- **`"error"`** - `callback(error)`: - Emitted when a parse error is encountered. This indicates that the message is malformed. - - -### stream.part - -The current part being processed. This is important, for instance, when -responding to the `body` event. - -### stream.isMultiPart - -True if the stream is a multipart message. Generally this will be true, but -non-multipart messages will behave the same as a multipart message with a -single part, and `isMultiPart` will be set to `false`. - -### stream.parts - -An array of the parts contained within the message. Each is a `part` object. - -### stream.pause - -If the underlying message supports pause and resume, then this will pause the -stream. - -### stream.resume - -If the underlying message supports pause and resume, then this will resume the -paused stream. - -### multipart.Part - -As it parses the message, the Stream object will create `Part` objects. - -### part.parent - -The message that contains this part. - -### part.headers - -The headers object for this message. - -### part.filename - -The filename, if specified in the `content-disposition` or `content-type` -header. For uploads, downloads, and attachments, this is the intended filename -for the attached file. - -### part.name - -The name, if specified in the `content-disposition` or `content-type` header. -For `multipart/form-data` messages, this is the name of the field that was -posted, and the body specifies the value. - -### part.isMultiPart - -True if this part is a multipart message. - -### part.parts - -Array of children contained within a multipart message, or falsey. - -### part.boundary - -For multipart messages, this is the boundary that separates subparts. - -### part.type - -For multipart messages, this is the multipart type specified in the -`content-type` header. For example, a message with `content-type: multipart/form-data` will have a `type` property of `form-data`. - -### Example - -Here is an example for parsing a `multipart/form-data` request: - - - var multipart = require("multipart"), - sys = require("sys"), - http = require("http"); - http.createServer(function (req, res) { - var mp = multipart.parse(req), - fields = {}, - name, filename; - mp.addListener("error", function (er) { - res.writeHead(400, {"content-type":"text/plain"}); - res.write("You sent a bad message!\n"+er.message); - res.close(); - }); - mp.addListener("partBegin", function (part) { - name = part.name; - filename = part.filename; - if (name) fields[name] = ""; - }); - mp.addListener("body", function (chunk) { - if (name) { - // just a demo. in reality, you'd probably - // want to sniff for base64 encoding, decode, - // and write the bytes to a file or something. - if (fields[name].length > 1024) return; - fields[name] += chunk; - } - }); - mp.addListener("complete", function () { - var response = "You posted: \n" + sys.inspect(fields); - res.writeHead(200, { - "content-type" : "text/plain", - "content-length" : response.length - }); - res.write(response); - res.close(); - }) - }); - - -### Nested Multipart Messages - -Nested multipart parsing is supported. The `stream.part` object always refers -to the current part. If `part.isMultiPart` is set, then that part is a -multipart message, which contains other parts. You can inspect its `parts` -array to see the list of sub-parts, which may also be multipart, and contain -sub-parts. ## TCP diff --git a/lib/multipart.js b/lib/multipart.js deleted file mode 100644 index 54db1e93d4d..00000000000 --- a/lib/multipart.js +++ /dev/null @@ -1,437 +0,0 @@ - -var sys = require("sys"), - events = require("events"), - wrapExpression = /^[ \t]+/, - multipartExpression = new RegExp( - "^multipart\/(" + - "mixed|rfc822|message|digest|alternative|" + - "related|report|signed|encrypted|form-data|" + - "x-mixed-replace|byteranges)", "i"), - boundaryExpression = /boundary=([^;]+)/i, - CR = "\r", - LF = "\n", - CRLF = CR+LF, - MAX_BUFFER_LENGTH = 16 * 1024, - - // parser states. - s = 0, - S_NEW_PART = s++, - S_HEADER = s++, - S_BODY = s++; - -exports.parse = parse; -exports.cat = cat; -exports.Stream = Stream; - -// Parse a streaming message to a stream. -// If the message has a "body" and no "addListener", then -// just take it in and write() the body. -function parse (message) { - return new Stream(message); -}; - -// WARNING: DONT EVER USE THE CAT FUNCTION IN PRODUCTION WEBSITES!! -// It works pretty great, and it's a nice test function. But if -// you use this function to parse an HTTP request from a live web -// site, then you're essentially giving the world permission to -// rack up as much memory usage as they can manage. This function -// buffers the whole message, which is very convenient, but also -// very much the wrong thing to do in most cases. -function cat (message, callback) { - var stream = parse(message); - stream.files = {}; - stream.fields = {}; - stream.addListener("partBegin", function (part) { - if (part.filename) stream.files[part.filename] = part; - if (part.name) stream.fields[part.name] = part; - }); - stream.addListener("body", function (chunk) { - stream.part.body = (stream.part.body || "") + chunk; - }); - stream.addListener("error", function (e) { p.emitError(e) - if (callback) callback(e); - }); - stream.addListener("complete", function () { - if (callback) callback(null, stream); - }); -}; - -// events: -// "partBegin", "partEnd", "body", "complete" -// everything emits on the Stream directly. -// the stream's "parts" object is a nested collection of the header objects -// check the stream's "part" member to know what it's currently chewin on. -// this.part.parent refers to that part's containing message (which may be -// the stream itself) -// child messages inherit their parent's headers -// A non-multipart message looks just like a multipart message with a -// single part. -function Stream (message) { - var isMultiPart = multipartHeaders(message, this), - w = isMultiPart ? writer(this) : simpleWriter(this), - e = ender(this); - if (message.addListener) { - message.addListener("data", w); - message.addListener("end", e); - if (message.pause && message.resume) { - this._pause = message; - } - } else if (message.body) { - var self = this; - if (message.body.pause && message.body.resume) { - this._pause = message.body; - } - if (message.body.addListener) { - message.body.addListener("data", w); - message.body.addListener("end", e); - } if (message.body.forEach) { - var p = message.body.forEach(w); - if (p && p.addCallback) p.addCallback(e); - else e(); - } else { - // just write a string. - w(message.body); - e(); - } - } -}; -Stream.prototype = { - __proto__ : events.EventEmitter.prototype, - error : function (ex) { - this._error = ex; - this.emit("error", ex); - }, - pause : function () { - if (this._pause) return this._pause.pause(); - throw new Error("Unsupported"); - }, - resume : function () { - if (this._pause) return this._pause.resume(); - throw new Error("Unsupported"); - } -}; - -// check the headers of the message. If it wants to be multipart, -// then we'll be returning true. Regardless, if supplied, then -// stream will get a headers object that inherits from message's. -// If no stream object is supplied, then this function just inspects -// the message's headers for multipartness, and modifies the message -// directly. This divergence is so that we can avoid modifying -// the original message when we want a wrapper, but still have the -// info available when it's one of our own objects. -function multipartHeaders (message, stream) { - var field, val, contentType, contentDisposition = ""; - if (stream) stream.headers = {}; - for (var h in message.headers) if (message.headers.hasOwnProperty(h)) { - val = message.headers[h]; - field = h.toLowerCase(); - if (stream) stream.headers[field] = val; - if (field === "content-type") { - contentType = val; - } else if (field === "content-disposition") { - contentDisposition = val; - } - } - - if (!Array.isArray(contentDisposition)) { - contentDisposition = contentDisposition.split(","); - } - contentDisposition = contentDisposition[contentDisposition.length - 1]; - - var mutate = (stream || message); - - // Name and filename can come along with either content-disposition - // or content-type. Well-behaved agents use CD rather than CT, - // but sadly not all agents are well-behaved. - [contentDisposition, contentType].forEach(function (h) { - if (!h) return; - var cd = h.split(/; */); - cd.shift(); - for (var i = 0, l = cd.length; i < l; i ++) { - var bit = cd[i].split("="), - name = bit.shift(), - val = stripQuotes(bit.join("=")); - if (name === "filename" || name === "name") { - mutate[name] = val; - } - } - }); - - if (!contentType) { - return false; - } - - // legacy - // TODO: Update this when/if jsgi-style headers are supported. - // this will keep working, but is less efficient than it could be. - if (!Array.isArray(contentType)) { - contentType = contentType.split(","); - } - contentType = contentType[contentType.length-1]; - - // make sure it's actually multipart. - var mpType = multipartExpression.exec(contentType); - if (!mpType) { - return false; - } - - // make sure we have a boundary. - var boundary = boundaryExpression.exec(contentType); - if (!boundary) { - return false; - } - - mutate.type = mpType[1]; - mutate.boundary = "--" + boundary[1]; - mutate.isMultiPart = true; - - return true; -}; -function simpleWriter (stream) { - stream.part = stream; - stream.type = false; - var started = false; - return function (chunk) { - if (!started) { - stream.emit("partBegin", stream); - started = true; - } - stream.emit("body", chunk); - }; -} -function writer (stream) { - var buffer = "", - state = S_NEW_PART, - part = stream.part = stream; - stream.parts = []; - stream.parent = stream; - return function (chunk) { - if (stream._error) return; - // write to the buffer, and then process the buffer. - buffer += chunk; - while (buffer.length > 0) { - while (buffer.substr(0, 2) === CRLF) buffer = buffer.substr(2); - switch (state) { - case S_NEW_PART: - // part is a multipart message. - // we're either going to start reading a new part, or we're going to - // end the current part, depending on whether the boundary has -- at - // the end. either way, we expect --boundary right away. - var boundary = part.boundary, - len = boundary.length, - offset = buffer.indexOf(boundary); - if (offset === -1) { - if (buffer.length > MAX_BUFFER_LENGTH) { - return stream.error(new Error( - "Malformed: boundary not found at start of message")); - } - // keep waiting for it. - return; - } - if (offset > 0) { - return stream.error(Error("Malformed: data before the boundary")); - } - if (buffer.length < (len + 2)) { - // we'll need to see either -- or CRLF after the boundary. - // get it on the next pass. - return; - } - if (buffer.substr(len, 2) === "--") { - // this message is done. - // chomp off the boundary and crlf and move up - if (part !== stream) { - // wait to see the crlf, unless this is the top-level message. - if (buffer.length < (len + 4)) { - return; - } - if (buffer.substr(len+2, 2) !== CRLF) { - return stream.error(new Error( - "Malformed: CRLF not found after boundary")); - } - } - buffer = buffer.substr(len + 4); - stream.emit("partEnd", part); - stream.part = part = part.parent; - state = S_NEW_PART; - continue; - } - if (part !== stream) { - // wait to see the crlf, unless this is the top-level message. - if (buffer.length < (len + 2)) { - return; - } - if (buffer.substr(len, 2) !== CRLF) { - return stream.error(new Error( - "Malformed: CRLF not found after boundary")); - } - } - // walk past the crlf - buffer = buffer.substr(len + 2); - // mint a new child part, and start parsing headers. - stream.part = part = startPart(part); - state = S_HEADER; - continue; - case S_HEADER: - // just grab everything to the double crlf. - var headerEnd = buffer.indexOf(CRLF+CRLF); - if (headerEnd === -1) { - if (buffer.length > MAX_BUFFER_LENGTH) { - return stream.error(new Error( - "Malformed: header unreasonably long.")); - } - return; - } - var headerString = buffer.substr(0, headerEnd); - // chomp off the header and the empty line. - buffer = buffer.substr(headerEnd + 4); - try { - parseHeaderString(part.headers, headerString); - } catch (ex) { - return stream.error(ex); - } - multipartHeaders(part); - - // let the world know - stream.emit("partBegin", part); - - if (part.isMultiPart) { - // it has a boundary and we're ready to grab parts out. - state = S_NEW_PART; - } else { - // it doesn't have a boundary, and is about to - // start spitting out body bits. - state = S_BODY; - } - continue; - case S_BODY: - // look for part.parent.boundary - var boundary = part.parent.boundary, - offset = buffer.indexOf(boundary); - if (offset === -1) { - // emit and wait for more data, but be careful, because - // we might only have half of the boundary so far. - // make sure to leave behind the boundary's length, so that we'll - // definitely get it next time if it's on its way. - var emittable = buffer.length - boundary.length; - if (buffer.substr(-1) === CR) emittable -= 1; - if (buffer.substr(-2) === CRLF) emittable -= 2; - - if (emittable > 0) { - stream.emit("body", buffer.substr(0, emittable)); - buffer = buffer.substr(emittable); - } - // haven't seen the boundary, so wait for more bytes. - return; - } - if (offset > 0) { - var emit = buffer.substr(0, offset); - if (emit.substr(-2) === CRLF) emit = emit.substr(0, emit.length-2); - if (emit) stream.emit("body", emit); - buffer = buffer.substr(offset); - } - - // let em know we're done. - stream.emit("partEnd", part); - - // now buffer starts with boundary. - if (buffer.substr(boundary.length, 2) === "--") { - // message end. - // parent ends, look for a new part in the grandparent. - stream.part = part = part.parent; - stream.emit("partEnd", part); - stream.part = part = part.parent; - state = S_NEW_PART; - buffer = buffer.substr(boundary.length + 4); - } else { - // another part coming for the parent message. - stream.part = part = part.parent; - state = S_NEW_PART; - } - continue; - } - } - }; -}; - -function parseHeaderString (headers, string) { - var lines = string.split(CRLF), - field, value, line; - for (var i = 0, l = lines.length; i < l; i ++) { - line = lines[i]; - if (line.match(wrapExpression)) { - if (!field) { - throw new Error("Malformed. First header starts with whitespace."); - } - value += line.replace(wrapExpression, " "); - continue; - } else if (field) { - // now that we know it's not wrapping, put it on the headers obj. - affixHeader(headers, field, value); - } - line = line.split(":"); - field = line.shift().toLowerCase(); - if (!field) { - throw new Error("Malformed: improper field name."); - } - value = line.join(":").replace(/^\s+/, ""); - } - // now affix the last field. - affixHeader(headers, field, value); -}; - -function affixHeader (headers, field, value) { - if (!headers.hasOwnProperty(field)) { - headers[field] = value; - } else if (Array.isArray(headers[field])) { - headers[field].push(value); - } else { - headers[field] = [headers[field], value]; - } -}; - -function startPart (parent) { - var part = { - headers : {}, - parent : parent - }; - parent.parts = parent.parts || []; - parent.parts.push(part); - return part; -}; - -function ender (stream) { return function () { - if (stream._error) return; - if (!stream.isMultiPart) stream.emit("partEnd", stream); - stream.emit("complete"); -}}; - -function stripslashes(str) { - // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + improved by: Ates Goral (http://magnetiq.com) - // + fixed by: Mick@el - // + improved by: marrtins - // + bugfixed by: Onno Marsman - // + improved by: rezna - // + input by: Rick Waldron - // + reimplemented by: Brett Zamir (http://brett-zamir.me) - // * example 1: stripslashes("Kevin\'s code"); - // * returns 1: "Kevin's code" - // * example 2: stripslashes("Kevin\\\'s code"); - // * returns 2: "Kevin\'s code" - return (str+"").replace(/\\(.?)/g, function (s, n1) { - switch(n1) { - case "\\": - return "\\"; - case "0": - return "\0"; - case "": - return ""; - default: - return n1; - } - }); -}; -function stripQuotes (str) { - str = stripslashes(str); - return str.substr(1, str.length - 2); -}; diff --git a/src/node.cc b/src/node.cc index 4965237024c..99852cecf12 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1199,7 +1199,6 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("http_old"), String::New(native_http_old)); exports->Set(String::New("ini"), String::New(native_ini)); exports->Set(String::New("mjsunit"), String::New(native_mjsunit)); - exports->Set(String::New("multipart"), String::New(native_multipart)); exports->Set(String::New("net"), String::New(native_net)); exports->Set(String::New("posix"), String::New(native_posix)); exports->Set(String::New("querystring"), String::New(native_querystring)); diff --git a/test/fixtures/multipart.js b/test/fixtures/multipart.js deleted file mode 100644 index 726fec7e5a8..00000000000 --- a/test/fixtures/multipart.js +++ /dev/null @@ -1,721 +0,0 @@ - -// each message contains a header, body, and a list of the parts that are -// expected. Any properties in the expected objects will be matched against -// the parsed parts. - -var messages = exports.messages = []; - -var bad = exports.badMessages = []; - -var longString = ""; -for (var i = 0; i < (16*1024); i ++) longString += Math.random(); - -// content before the first boundary -bad.push({ - headers : { "Content-Type":"multipart/mixed; boundary=boundary" }, - body : "blerg\r\n--boundary\r\nblarggghhh" -}); -// no boundary -bad.push({ - headers : { "Content-Type":"multipart/mixed; boundary=boundary" }, - body : longString -}); -// header unreasonably long. -bad.push({ - headers : { "Content-Type":"multipart/mixed; boundary=boundary" }, - body : "--boundary\r\ncontent-type: "+longString+"\r\n"+longString -}); -// CRLF not found after boundary -bad.push({ - headers : { "Content-Type":"multipart/mixed; boundary=boundary" }, - body : "--boundary"+longString -}); -// start first header with whitespace. -bad.push({ - headers : { "Content-Type":"multipart/mixed; boundary=boundary" }, - body : "--boundary\r\n fail: blahrg\r\n\r\n"+longString -}); - -// The comments in this first test case tell a story about what the parser is -// doing at each step. If you mean to touch the code, it's best to read through -// this test case first so that you know what you're getting into. -messages.push({ - expect : [ - { type : "mixed", boundary : "--inner1" }, - { type : "mixed", boundary : "--inner2" }, - { filename : "hello.txt" }, - { filename : "hello2.txt" }, - { type : "mixed", boundary : "--inner3" }, - { filename : "hello3.txt" }, - { filename : "hello4.txt" }, - { filename : "hello-outer.txt" } - ], - headers : { - "Content-Type":"multipart/mixed; boundary=outer" - }, body : [ - // s=new part, part = stream, part.boundary=--outer - "--outer",// chomp to here, because it matches the boundary. - // mint a new part without a boundary, parent=old part, set state to header - "Content-Type: multipart/mixed; boundary=inner1",// move along - "", // found the end of the header. chomp to here, parse the headers onto - // the current part. Once we do that, we know that the current part - // is multipart, and has a boundary of --inner1 - // s=new part, part = --inner1 - "--inner1", // chomp to here. - // mint a new part without a boundary, parent=--inner1, s=header - "Content-type: multipart/mixed; boundary=inner2", // move along - "", // again, found the end of the header. chomp to here, parse headers - // onto the newly minted part. Then find out that this part has a - // boundary of --inner2. - // s=new part, part=--inner2 - "--inner2", // chomp to here. - // mint a new part without a boundary, parent=--inner2 - "Content-type: text/plain", // move along - "content-disposition: inline; filename=\"hello.txt\"", // move along - "", // chomp to here. found end of header. parse headers - // then we know that it's not multipart, so we'll be looking for - // the parent's boundary and emitting body bits. - // also, we can set part.filename to "hello.txt" - // s=body, part=hello.txt - "hello, world", // chomp, emit the body, looking for parent-boundary - "--inner2", // found parent.boundary. leave it on the buffer, and - // set part=part.parent, s=new part - // on the next pass, we'll chomp to here, mint a new part - // without a boundary, set s=header - "content-type: text/plain", // header... - "content-disposition: inline; filename=\"hello2.txt\"", // header... - "", // chomp to here, parse header onto the current part. - // since it's not multipart, we're looking for parent.boundary - "hello to the world", // body, looking for parent.boundary=--inner - "--inner2--", // found parent.boundary. In this case, we have the - // trailing --, indicating that no more parts are coming - // for this set. We need to back up to the grandparent, - // and then do the new part bit. Chomp off the --inner2-- - // s=new part, part=part.parent.parent=--inner1 - "--inner1", // chomp to here, because this is part.boundary - // mint a new part without a boundary - // s=header, part = (new) - "Content-type: multipart/mixed; boundary=inner3", // header... - "", // chomp to here, parse headers onto the new part. - // it's multipart, so set the boundary=--inner3, - // s=new part, part = --inner3 - "--inner3", // chomp to here. mint a new part with no boundary, parse headers - "Content-type: text/plain", // header - "content-disposition: inline; filename=\"hello3.txt\"", // header - "", // end of header. parse headers onto part, whereupon we find that it is - // not multipart, and has a filename of hello3.txt. - // s=body, part=hello3.txt, looking for part.parent.boundary=--inner3 - "hello, free the world", // body... - "--inner3", // found parent.boundary, and it's not the end. - // s = new part, part = part.parent - // next pass: - // mint a new part without a boundary, s=header - "content-type: text/plain", // header - "content-disposition: inline; filename=\"hello4.txt\"", // header - "", // chomp to here, parse headers on to boundaryless part. - // s=body, part = hello4.txt - "hello for the world", // body, looking for part.parent.boundary=--inner3 - "--inner3--", // found parent.boundary, and it's the end - // chomp this off the buffer, part = part.parent.parent=--inner1 - // s = new part - "--inner1", // chomp to here, because part.boundary = --inner1 - // mint a new boundariless part, s = header - "Content-type: text/plain", // header... - "content-disposition: inline; filename=\"hello-outer.txt\"", // header... - "", // chomp to here, parse headers onto the current part. - // has no boundary, so we're gonna go into body mode. - // s = body, boundary = parent.boundary = --inner1, part = hello-outer.txt - "hello, outer world", // body, looking for parent.boundary=--inner1 - "--inner1--", // found the parent.boundary, and it's the end. - // chomp off the --inner1--, part = part.parent.parent, s = new part - "--outer--" // we're looking for a new part, but found the ending. - // chomp off the --outer--, part = part.parent, s = new part. - ].join("\r\n") -}); - -messages.push({ - headers : { - "Content-Type": "multipart/form-data; boundary=AaB03x", - }, - body : [ - "--AaB03x", - "content-disposition: form-data; name=\"reply\"", - "", - "yes", - "--AaB03x", - "content-disposition: form-data; name=\"fileupload\"; filename=\"dj.jpg\"", - "Content-Type: image/jpeg", - "Content-Transfer-Encoding: base64", - "", - "/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg", - "--AaB03x--", "" - ].join("\r\n"), - expect : [ - { name : "reply" }, - { name : "fileupload", filename : "dj.jpg" } - ] -}); - -// one that's not multipart, just for kicks. -// verify that it ducks as a multipart message with one part. -messages.push({ - headers: { "content-type" : "text/plain" }, - body : "Hello, world!", - - // not much to say about this one, since it's just - // validating that a part was created, not that it has - // any particular properties. - expect : [{}] -}); - -// An actual email message sent from felixge to isaacs. -// Addresses and signatures obscured, but the unicycle pic is preserved for posterity. -messages.push({ - headers: { - // TODO: When node's parser supports header-wrapping, these should actually be wrapped, - // because that's how they appear in real life. - "Delivered-To":"isaacs...@gmail.com", - "Received":"by 10.142.240.14 with SMTP id n14cs252101wfh; Wed, 3 Feb 2010 14:24:08 -0800 (PST)", - "Received":"by 10.223.4.139 with SMTP id 11mr194455far.61.1265235847416; Wed, 03 Feb 2010 14:24:07 -0800 (PST)", - "Return-Path":"", - "Received":"from mail-fx0-f219.google.com (mail-fx0-f219.google.com [209.85.220.219]) by mx.google.com with ESMTP id d13si118373fka.17.2010.02.03.14.24.05; Wed, 03 Feb 2010 14:24:06 -0800 (PST)", - "Received-SPF":"neutral (google.com: 209.85.220.219 is neither permitted nor denied by best guess record for domain of isaacs+caf_=isaacs...=gmail.com@izs.me) client-ip=209.85.220.219;", - "Authentication-Results":"mx.google.com; spf=neutral (google.com: 209.85.220.219 is neither permitted nor denied by best guess record for domain of isaacs+caf_=isaacs...=gmail.com@izs.me) smtp.mail=isaacs+caf_=isaacs...=gmail.com@izs.me; dkim=pass (test mode) header.i=@gmail.com", - "Received":"by mail-fx0-f219.google.com with SMTP id 19so626487fxm.25 for ; Wed, 03 Feb 2010 14:24:05 -0800 (PST)", - "Received":"by 10.216.91.15 with SMTP id g15mr146196wef.24.1265235845694; Wed, 03 Feb 2010 14:24:05 -0800 (PST)", - "X-Forwarded-To":"isaacs...@gmail.com", - "X-Forwarded-For":"isaacs@izs.me isaacs...@gmail.com", - "Delivered-To":"i@izs.me", - "Received":"by 10.216.12.146 with SMTP id 18cs33122wez; Wed, 3 Feb 2010 14:24:00 -0800 (PST)", - "Received":"by 10.213.97.28 with SMTP id j28mr2627124ebn.82.1265235838786; Wed, 03 Feb 2010 14:23:58 -0800 (PST)", - "Return-Path":"", - "Received":"from ey-out-2122.google.com (ey-out-2122.google.com [74.125.78.25]) by mx.google.com with ESMTP id 4si11869270ewy.8.2010.02.03.14.23.54; Wed, 03 Feb 2010 14:23:57 -0800 (PST)", - "Received-SPF":"pass (google.com: domain of hai...@gmail.com designates 74.125.78.25 as permitted sender) client-ip=74.125.78.25;", - "Received":"by ey-out-2122.google.com with SMTP id d26so431288eyd.17 for ; Wed, 03 Feb 2010 14:23:54 -0800 (PST)", - "DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:received:from:date :x-google-sender-auth:message-id:subject:to:content-type; bh=JXfvYIRzerOieADuqMPGlnlFbIGyPuTssL5icEtSLWw=; b=QDzgOCEbYk8cEdBe+HYx/MJrTWmZyx4qENADOcnnn9Xuk1Q6e/c7b3UsvLf/sMoYrG z96RQhUVOKi9IAzkQhNnOCWDuF1KNxtFnCGhEXMARXBM3qjXe3QmAqXNhJrI0E9bMeme d5aX5GMrz5mIark462cDsTmrFgaYE6JtwASho=", - "DomainKey-Signature":"a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:from:date:x-google-sender-auth:message-id :subject:to:content-type; b=VYkN8OeNNJyxAseCAPH8u2aBfGmZaFesmieoWEDymQ1DsWg/aXbaWt4JGQlefIfmMK hOXd4EN2/iEix10aWDzKpuUV9gU9Wykm93t3pxD7BCz50Kagwp7NVyDJQLK0H5JSNEU/ IVRp90kKNBsb3v76vPsQydi9awLh/jYrFQVMY=", - "MIME-Version":"1.0", - "Sender":"hai...@gmail.com", - "Received":"by 10.216.86.201 with SMTP id w51mr154937wee.8.1265235834101; Wed, 03 Feb 2010 14:23:54 -0800 (PST)", - "From":"Felix Geisendoerfer ", - "Date":"Wed, 3 Feb 2010 23:23:34 +0100", - "X-Google-Sender-Auth":"0217977a92fcbed0", - "Message-ID":"<56dbc1211002031423g750ba93fs4a2f22ce22431590@mail.gmail.com>", - "Subject":"Me on my unicycle", - "To":"i@izs.me", - "Content-Type":"multipart/mixed; boundary=0016e6d99d0572dfaf047eb9ac2e", - }, - expect : [ - { type : "alternative", boundary : "--0016e6d99d0572dfa5047eb9ac2c" }, - {}, // the first bit, text/plain - {}, // the second bit, text/html - { name : "unicycle.jpg", filename : "unicycle.jpg" } - ], - body : [ - "--0016e6d99d0572dfaf047eb9ac2e", // beginpart->header - "Content-Type: multipart/alternative; boundary=0016e6d99d0572dfa5047eb9ac2c", // headers. isMultipart - "", // bodybegin->beginpart - "--0016e6d99d0572dfa5047eb9ac2c",//header - "Content-Type: text/plain; charset=ISO-8859-1", - "",//bodybegin->body - "*This was 4 years ago, I miss riding my unicycle !*", - "", - "-- fg", - "", - "--0016e6d99d0572dfa5047eb9ac2c", //partend->partbegin - "Content-Type: text/html; charset=ISO-8859-1", - "", - "This was 4 years ago, I miss riding my unicycle !

-- fg

", - "", - "", - "
", - "", - "--0016e6d99d0572dfa5047eb9ac2c--",//partend, walk up tree-->partbegin - "--0016e6d99d0572dfaf047eb9ac2e",//beginpart->header - "Content-Type: image/jpeg; name=\"unicycle.jpg\"",//header - "Content-Disposition: attachment; filename=\"unicycle.jpg\"",//header - "Content-Transfer-Encoding: base64",//header - "X-Attachment-Id: f_g58opqah0",//header - "",//bodybegin->body - "/9j/4AAQSkZJRgABAQEASABIAAD/4gUoSUNDX1BST0ZJTEUAAQEAAAUYYXBwbAIgAABzY25yUkdC",//bodybodybody - "IFhZWiAH0wAHAAEAAAAAAABhY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAA",//bodybodybody - "AADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAty",//bodybodybody - "WFlaAAABCAAAABRnWFlaAAABHAAAABRiWFlaAAABMAAAABR3dHB0AAABRAAAABRjaGFkAAABWAAA",//bodybodybody - "ACxyVFJDAAABhAAAAA5nVFJDAAABhAAAAA5iVFJDAAABhAAAAA5kZXNjAAABlAAAAD1jcHJ0AAAE", - "1AAAAEFkc2NtAAAB1AAAAv5YWVogAAAAAAAAdEsAAD4dAAADy1hZWiAAAAAAAABacwAArKYAABcm", - "WFlaIAAAAAAAACgYAAAVVwAAuDNYWVogAAAAAAAA81IAAQAAAAEWz3NmMzIAAAAAAAEMQgAABd7/", - "//MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsY3VydgAAAAAAAAABAjMAAGRlc2MAAAAAAAAAE0Nh", - "bWVyYSBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAE0NhbWVyYSBSR0IgUHJvZmlsZQAAAABtbHVjAAAA", - "AAAAAA8AAAAMZW5VUwAAACQAAAKeZXNFUwAAACwAAAFMZGFESwAAADQAAAHaZGVERQAAACwAAAGY", - "ZmlGSQAAACgAAADEZnJGVQAAADwAAALCaXRJVAAAACwAAAJybmxOTAAAACQAAAIObm9OTwAAACAA", - "AAF4cHRCUgAAACgAAAJKc3ZTRQAAACoAAADsamFKUAAAABwAAAEWa29LUgAAABgAAAIyemhUVwAA", - "ABoAAAEyemhDTgAAABYAAAHEAEsAYQBtAGUAcgBhAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBpAGwA", - "aQBSAEcAQgAtAHAAcgBvAGYAaQBsACAAZgD2AHIAIABLAGEAbQBlAHIAYTCrMOEw6QAgAFIARwBC", - "ACAw1zDtMNUwoTCkMOtleE9NdvhqXwAgAFIARwBCACCCcl9pY8+P8ABQAGUAcgBmAGkAbAAgAFIA", - "RwBCACAAcABhAHIAYQAgAEMA4QBtAGEAcgBhAFIARwBCAC0AawBhAG0AZQByAGEAcAByAG8AZgBp", - "AGwAUgBHAEIALQBQAHIAbwBmAGkAbAAgAGYA/AByACAASwBhAG0AZQByAGEAc3b4ZzoAIABSAEcA", - "QgAgY8+P8GWHTvYAUgBHAEIALQBiAGUAcwBrAHIAaQB2AGUAbABzAGUAIAB0AGkAbAAgAEsAYQBt", - "AGUAcgBhAFIARwBCAC0AcAByAG8AZgBpAGUAbAAgAEMAYQBtAGUAcgBhznS6VLd8ACAAUgBHAEIA", - "INUEuFzTDMd8AFAAZQByAGYAaQBsACAAUgBHAEIAIABkAGUAIABDAOIAbQBlAHIAYQBQAHIAbwBm", - "AGkAbABvACAAUgBHAEIAIABGAG8AdABvAGMAYQBtAGUAcgBhAEMAYQBtAGUAcgBhACAAUgBHAEIA", - "IABQAHIAbwBmAGkAbABlAFAAcgBvAGYAaQBsACAAUgBWAEIAIABkAGUAIABsIBkAYQBwAHAAYQBy", - "AGUAaQBsAC0AcABoAG8AdABvAAB0ZXh0AAAAAENvcHlyaWdodCAyMDAzIEFwcGxlIENvbXB1dGVy", - "IEluYy4sIGFsbCByaWdodHMgcmVzZXJ2ZWQuAAAAAP/hAIxFeGlmAABNTQAqAAAACAAGAQYAAwAA", - "AAEAAgAAARIAAwAAAAEAAQAAARoABQAAAAEAAABWARsABQAAAAEAAABeASgAAwAAAAEAAgAAh2kA", - "BAAAAAEAAABmAAAAAAAAAEgAAAABAAAASAAAAAEAAqACAAQAAAABAAAAyKADAAQAAAABAAABWwAA", - "AAD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0O", - "Dg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4O", - "Dg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAFbAMgDASIAAhEBAxEB/8QAHwAAAQUBAQEB", - "AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh", - "ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ", - "WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG", - "x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAEC", - "AwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB", - "CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0", - "dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX", - "2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4KEuQBkZp3m+5PaskTDPUUhmweDVt", - "kamt5+M89KkWf5uv4VifaDilFwS/PFK47tnQed6HB9KcJ+eTWIs/qTTvtB5OaQ7G35/uKd54PfrW", - "H9oyev40Cfn/AOvSBI+r/gxtfwHqZIz/AKZge3yivXGBB6c+gryL4HMz/CzUG2LtOoEbsf7Ir2V0", - "OR7mpluM8y1kL/wkN0B/ewePasRox5hwBW3rKg+KL3uPM/oKy227h0zUgZ72ykSE4yOvesu40xWT", - "IUZPbFdIkYZiR0+lOeINKQp7daTVxp2PM77w8kis2wAkccVxl7ocsQY7N2PQV7ubdSpUjK+9ZVzp", - "iOp46jpWUolxnY8ZsdU1PSm2A/aLccGN+ePY12HhnxLLpOqveeFNRk0C+kO6ewlG60uT/tJ6/wC0", - "uDV7UfDqkMVTk9K4+90J0TdsII7jqKiSvozrw2InRlzU3Zn1v4U+MGk380On+K4B4X1V8Kksj5s5", - "z/sS9if7rYP1r3CIq0aupVlIyrA5BHrX5q2+rX9lbta3ca6lYMMPFMM8enPWvW/BHje78M2sc9nr", - "80GgkH/iVahmRF/65sTmP6ZI9qiztofVYHP4zXLWVn+B9uoVC59qtoQTivhg/tDalZ+OSZbiO40r", - "zgfLBU7Bnnkdsdq9a8N/tBeErrWZrfUr+O3tmcC2lUZ2j/aOaV31R20s2w83a9j6WKLJGUYBlI5B", - "HWuR1PwhbzRytZgBnJYxk8ZJycV01he2t/p0N1ZXEVzbSANHLGwZWHqCK0QcMDx1FNM2xODpYiNp", - "K/mfKHizw9a2+mSx3U8VlKgAzI4QqeOuenNFdl8aNR8InxXbaHq9z9k1uSz+1W8ZiBW8TzSvl5Pc", - "EE44zRXlYvmVTSCZ+Z5hhalKvKCV7HyJr3wM120R5/D19b6zb4yIZCIpvw/hb8xXjGqaXq+i3xtd", - "X06802cH7txEUz9D0P4V3mmeKfFPhLwPpmp6dq920c8pBtpj5kRA9j0/CvUrH4waZqXhe2Xx34bg", - "l0+4OwTRxiVCe5KNyPwNfQqfcHqfLnnYXrzTllyfSvqCf4W/DTxvC114L15NLu3XIgR96A+hjY7l", - "/A15J4j+D3jnw0XmfTv7YsV5+0acTIAPdfvD8vxquZAlY4ETHHXNOEvufzqkVdZGRwyOpwykYIP0", - "qQKSKbAtiXPOeaXzeepNQrGcdTUoj55zRYD7A+ArsPhFfZ5V9RbGfUKte3sCUDE14v8AAmJR8E7h", - "skn+0ZMc+y17MwYwEjt2B61MtwPMNYwPE17tJx5v9KyfldguBnuRWnqR3eIrzP8Az0ql5QMxPB9h", - "SAdAu4HBxjmggAsxzUmAsRx1zzk4qB7mzgTdLcQIvffIKtUqj2ixcyJY1DZY9utI8SmMYBJIxUUe", - "pWG13S8tZFAywRwxx9BUsN7ZXty0FrdW0su3cEVxkj1q5YWskm4v7hc8e5G1skkA+X2INY9xpqnO", - "Uziur8p1XaVOQM4xXOeK/EOk+EPB39ua9K1tYmZIU2pueR26BV6noT9BWDpS2sWpHHalpFlFaNdX", - "J8iBOXbHavLfEV5pl5cm1toxE7AIuc4CjgZ/niu18Y61q2t/DbS9S8PeF/ENzpt3deWjXNhJAZHP", - "CYDAZXPccV4VfW+o2OvzWGoRqlzE21wueG6MAfbpmud2TPTpUZqHM0Y3im7trK3NhaXLb/SFMAms", - "XQmu7aG686WSVVQMCD80ZPfnr7ir9/Aq6rGr25t4hzJI5+Zj7VHdTR2kDm0C+UxXcW9O9aRemopJ", - "3ufXH7MfxGutA8W6lpWvancN4entfMjEm5hFNuAGB2BGentX6IQXcF3YLc2siTQOuUdTkMK/D7Sf", - "FFxpF9HNZvIFZt7KT+GB+Ffor8K/ixLafCDSl1ez+06UI2BuIZB51vg870P3l75HI9KwqRs9D3sp", - "zFRtTqPToaX7RnhvTtX8RaVfzWtxLqP2J7a1mt03SRlpGPyjo3UnB9M8UVt+MviNpNn8WvCutW1w", - "t/4XvrB4ZL6BN6W7mQ4Y56EcZBwcUV59blc78x8vnOJccZUSl1PgvXbiMfBLwo7N5YkdyN1S66q/", - "8KP8KupU75HOQetZfirK/BPwWnXKuf8A69SeLd0fwI8CqrbCVc8HFetzd+5z23Letwtpfw+8J3lm", - "z211IjOZImw2fqOa9LsviZ438JJokDXa69b3VqJXivvmZcns/wB4frXlvjSeSD4UeAsENusmJDc5", - "6Vs+LLwW3iPwhbGJnaTS4OAeBlhRowZ7bfeJ/hr4tuPsXjPw9/Y2rOoP2lU6Z9JU5/76Fcnq/wAG", - "bOWA3/hPX4NSs25WOZ1Yj2Drx+YFctqUgl/aStNMeFWiZolJJ7bc9KpaPNen4i+JhY3M2m/YkmlB", - "t3K7tp4yOho52thK7My98J3ukzbNRtLmDB4Yr8p+jDg10nh74b6/4ltDPoukSX0QOC3nIv48kGtD", - "SPiFrdx4NlvNYs7bUrSOZYXYLtkYn26H8q9++D11r9t4v1d5NGnsdNe2RYBND5eAWJOPzzVfWLbo", - "qNKUnorieA9Kv/BfgIaTrlm+nXEl07gNgrjA/iHFejrIW06S4w5t0QsZQh2ADvn0rb8VXWn3emxp", - "e3cUTIDwSO9VvDPi/TdN8Gz6DNqLX1nIrRiEnICHsPasPrcU3zM76eV4iotInjLX2n6j4h1CW2u4", - "rm3WUl2hO8qK5zWfGWj6RDss4pLu9Y7I1bHze9e8XMOhHRr6DSNJsrQ3ELRmRIwG5BHWvz41y5ub", - "fxHqcM0pW4juGhxnlQDg17/D9ehWlK8btHJm2X1MMo3lueuT+K2mQvfX1vFu5Krwq+1YUnifQZg5", - "j1G3uCD8y+Xla+fvEeqM9x9nWdljUqCAeMYrEbVLey0IBMs8r/IPUDvX1UsaouyWiPEVFs9xutU0", - "k3DtbTLDIckNE/yj+orNm8S38ECvC0N3JC29m/ibtkY7+teIx6lIBLM5HmPwgHpSx6xfW1ws0UzI", - "2c46g/hXHLHpm0aLPZbb4sa/Z6gIvNMIBzGpkJCn0H+yfT61718JvF2n+K/EF5J4is7LVr6x2NYi", - "8jEixFidzKrZAPQZ618VyzWms2mIglpfL8wQH5ZPXb6H2rtvhb4wfwz8TLSeaXy45h9nnLdsng/g", - "QP1ryc0lUq4acYvU9fKJU6WLhKSP1G1bWN/hpsxfaLloyIkB2t07H+HA6Yr4w8f/AA9ujrPh620i", - "IG7mjkee6dy2xjg/MfXmvTJfF81yghhlDyn7x3dB7VoJq9tLaGeaZXIXABPIPrXwEJyTufpWIhSq", - "0uR7Hyx4i+F2saXZ/aTKNUfbhkTgp9PWvNbnR9Qi0xvtVncWxUhXMqEBueMV9P6z4hu/7ReGOI3c", - "Lk7Cv3lP+FWNH8Nah4i04STaenkNJtkEhBX3PNehSqTbSPn8ZhcPBN7WPjeCykkvoY0WSV1kHKjl", - "iTjA+gFfrZ8INZ8KaT+xZZ2Wqax4e0O/t7K4imgu1j86ZWV9sjjG4E5A5PbpXhsfwu8KWt/a3VvY", - "eTNBKX4YkOTyc59/yr7h07RtF039mA3M1rah/wCxTO08sSb95ik2ncR1+bCk+4Pau1JnylapF2SP", - "jnXrvwzffDDT7ZFEFxbLEguoxI0U+VGGI6EjkYx2A6UVpeItL1jTPhu062UR0i7srcy3IfckEgAC", - "q+T8rMCDgdyOe1FeLBUX/EvfyPEqUuaTcr3PjrxiCvwn8Epzxbsaf41GPgr4AXp/o7mjxoGPw78E", - "xqGLfZTwB9K3PFWg6hqXwq8DxWsQ3RWZLhjg817D/U9lQk9kYPxAXb8O/h8g/wCgcT/Ktbxum/4p", - "+DYh2022GP8AgQrT8ceEtdvfCvgmK1sxP9n04LKFcfKeK6XxH4H1zUPjB4auI44UghsbZWLN3U5I", - "qU9fmX7Gp2Mm4TzP2wbcdds6A/glbPw/8K6nr3xD8aC3t5EhmimiWZl4yXI49a9Etvh6sPxzl8S3", - "85aNZA6IOFHy45Ndbf8AjbSvCunS2+ixRm6ZjuZBgZNYVK0Yo9LCZTOes9EXPDXw28NeCPAJh1p1", - "upmlWdhJgncB6VW8QfFFIFe307ZGqjaCp5wOK8j1fxTrWus8ssj+UTyQeBTtN8GaxqOqi3kRo3Kh", - "zu7A1xSdWoz3VUw9COljP1bxNqWp3DNJPK2T611fhaO7aEXJE8qr/dUnNdW/wys9M0+KW7cyylCc", - "GvUfhpp1pH4HuFUwSeZJIPnQHaAePx7V00cGpbnnV87in7up5o+t65LKbWws7jzAMBQmDXy34y+H", - "PxN1r4o6xf6Z4c1Ca3ml8wSAAAkgZNfpPb6Wkt0kl1DEqrwiBQf/AK44960YreOKafynlAwSzM5C", - "4Hs2f0r0sFD6vNyj1PHx2OeJSUlsfjprvw58caPFJN4i0i60iBvmea6IHA9K4J41kvGcvuAG1MdA", - "K+pv2jPHcvjX4nS6Rp1213oumDyV8rgOwOWyewz+Jx2r5wSzdDvZQABwqjCivootygm9zyYu5nOo", - "igjJxuI6mq6xRyT5dmkP14rV1C0wTM2WjC/LUVlaiSVQFLMzhI1HVmPAAo5dSys9lIhDwMW/nUEs", - "rtKJCfLuF4bPG/8A+vXpT+FdWt9JFw+niSRWPmQCfDAe2OM+1cxqdmbjR5L7TVzHD8tzbTLmWI9y", - "aydSL2ZWpLpnxM1vSb21G77bDEQHSRcsV7jfnj8a+gY/iToF34UXU4tXt7KHyvngkwZA3cbep/Cv", - "ktbZ538yZmWIfwgAZprIn2jzdigD5YxXlVcvpzldKx6tDNa1OLTdz6Ktvixo7a1BINJupySFeSVg", - "u0Z6qP8AGvtDQoFtvC1pGoDbkEm5RgHdz/WvzK8K6Y+seOdJ0+PJkurtEUAdcsBn6Cv1ItY1gtY4", - "EJMcSBF+gGB/Koq4anSa5dzGvj61aHLN6BIAwI6k1uT/ABLceErvwzq1xYDSodPaGNJFOZmKYSPP", - "A6nJ9wtYsgPlsyk4r5x8Y3Ev9u3f2mdLSMx7raNHDNIwY4OOeMgHbke9ebjE2lY8jFTcbWPcvE/j", - "PQ5/2XtZtITDHcxyW8NxaCURGYArtbDDLYxyQcg5PTiivkwy6ne6LLbnTr+S6d1kDTxHymzuQ7e4", - "Ocf5FFec3OKSTOedeoupY1uxn1Cx8A2sB2P9k3E46AYzXtt1/Z1poGlRSWysgtwsbOcc968W13Uv", - "7H/4Qi5xlEssOPbIrY8ba1JH4S0m7LNi4TdEnTA9a9apfp3Psssq0oU5Oe56VFryp5ccttHIiphM", - "N0FbE3i3zoEdbeIXMOPKLHrXiXiPVzol14ciTP8ApdjHI2PU8Vp6leSWvxgstHTPlt5BOP8AbrPl", - "Z0vM6O6O8uvFupa3q66Uz+TKxJ2px26VxNhINQsPE0knzPZWzMD77sVZ0wFf2kbqPJ2RSSAD221p", - "fDbRJPEHiTxDpEYJN7IsTY7KZOT+WaSpRvc8uvmVWSsnoaeraBN4f+BHhWeZdmoatNFcS88qjv8A", - "KPyAr6JKCP4igIgUDT4gQB/tNXjvxS1WLVfEptbQL9gsNXgsrcL02xALxXt8iqPiLc5A40+H/wBC", - "arlboefzylq2V/FMmLWLnHyGqvw78T6MPDLWn2kxzpcyB8xk87iCM4xiovGshFjAVPBQ968i8J3H", - "2e0vlMsaRyXTscg55JziinUcXczaPr8ajpzWPmRahaXGV+dzIAx5xwK8q+Ml3qY+B19a6LPJFc3k", - "sdtLICS8EZPzuD67QQPrXIWF3GWC+bI6ocEA5yPXHY/WvGfiR48uri6vfDFjqF39kik/0uVFzhv7", - "ikdPevUwH76slbTqZ1XaJ4PrNppekxm3jKTSrnEKNkA+rHua4GVJbi73zgrGOQicCuhuZD5sgg0k", - "sc/eklJP41gXd3copEtlHEP9h+a+jqzjcxhF2KutBZNIgaMGOGOQB89ye/4U7wvbJffELSx5iJbW", - "7+cdxwDs5/EmqU99C+j3MILea4GFbjkVzkdy0UTRyIUlXhfp7etcVaSeiNUj6N8ReIrbTraa7jC3", - "UXnIrNFIPkB6mvGtY1eJvFmp3OhzXUFpeIBP5gwXP8X0Brl5JHkSGUO7RbMKCeAc+lXoYw5C5AUc", - "t71jClrqXsRkM6BQvUcL7VTlieW+8uNN0cY27jwue5Jq5e3aJKsMGHkPU/57UkUbvtVsgd81Vk9g", - "Z7t8AfBuseIvipNqWjWC6l/YsIuZhI+wSOx2ooOMDqxA/wBmvsptUfTdQNvren32jTZwxuYj5Z/4", - "GOP5Vt/smeCk0D9lr+3biEC+167a4CkYLQJ8kfPpkO3419LyaZZ6pE/2i1injP8AG0YIz+NeVine", - "ehasj5kWeGe28yGaOWJl+V0cEGvj3WPEcemeN9RtTZrcQLqc+2VgWWPe5BDDtzlsd8A1+gvjT4c6", - "BY6BqevwmTw+trGZpp7PKgDjLFBw+D1GMntXxx8UvA3h/wAGX9rqljqsmpX9w0dzm8j8mO7mZSZE", - "ii+8yA/xnGCcV5+Io88dTlxUVKxnQ6/pmoB5P7UjntPsxgzDYANsVwwVxyOx+oNFef6RBa3Ph7VN", - "ft54jdyztH9m88xRx5KqFOAchmICkkdD1ycFeTKjFO3M/wCvkedJSi7Ib4940fwquB/yDxUvj8t/", - "wjPguMH5f7MGR+VM8fDNp4YBGcaeOv1qT4gYOjeDQRn/AIla9Pwr2d7ep7qJviEAfEPg1PTTYf5i", - "um1ePd+05Z552i1H6VznxAXHjbwinYWEH/oQrqr8bv2n4+vDW/b/AGaS3Q+qNbS13ftFam47NNz/", - "AMBrofhbqD6FqviDXdjbYFYq+ON3zf41i6Sv/F+dWcDgGbqOnFeg3eixaD+yjaeZ8mp6sZL2QdCI", - "ywVP0FTqlcls87glkvPDlpdSEtJPrwkYnuSRX1bdHHxGvBzgWEHH/Anr5U0uPPhLRATydZT+Yr6n", - "vTj4l3ozyLGD/wBCepmrIqJj+L/nsoFHJ2GvLfCXhvW7nT7meDRb6VTcyNFMkOc5Y+pxXqPik/uo", - "R0JQ1t/DZ7hvAqyKyvCssmcS4Jwx456HNFKCk3ciTszyrUJb7ToZLqexuoLtV2mOWPZ5hHAO4jH1", - "r501s69JNM9xq2m6PbFiVtrOMMck5JLEZJ96+ivjd421+0vIdFewsjbLbi4WaVmLhjkY2qMcdj71", - "8OeINY1q5uWaKKBmztUESMSPX7or6zK6EMPQ5nuzkqNznZdBdQht/OkabXL24bJ3DzQoP4CuLZXS", - "5eRAzJngBy1VbuTWkVzdvBbjtyqE/nzWILy9SUGEoxHfdnP5VVSqpPY1jFmzMVExPlttx/d6VSmQ", - "PZyrtIliAkQ4rPmuHmy0sL+Z1JjlKkfSoIrq4W2dYLrdcsQCbj5WVfQdia55TRoi0rlNNmQHOJsJ", - "7ZGakjD3E8dqs6pLjO05+YntXUeA9J0rWfiHaW3iFpLXQ4Y5LrUJPM2kQxJlirD+InAAHrVq20Kw", - "ufFFxd6JYz28LzlrSKaVpGSPPG8nqccmuOvi1T0Z04fDSqySR02nfDayudHS6e+ube6dMspAdc/z", - "r6Z8Mfsa6lrPhTTdRufGkGlz3EIlmtG0tnaFW5X5hJySMZ44zXHfDrRJbnxbYWd9IblFcSTk8AKO", - "cD+VfX1hc3OmXJkivtQjKJhG8/BAJ7EdfpXkUMfVvdvQ7syoUqTjGK1PfPDulW/h3wJovh2xISz0", - "+zjtVRcA4RQu4keuP1rbT7RHHFGtypOeCy/Nn+uK8KtfFWqq6yzTLdAEqyyxgE++Rgk11sPj+0d0", - "+1Wc8DMoLHIYD0Yd/wAKv28Zas8qxtfEM3+o/AfxXp1jZR6jfT2LxWsYynmyEgAMR0BPOew5r5D+", - "JHgTXrvwHpVn4W8N/aHsImiGmCz3HzJ4v3032h3DMFcAKh44zgdK+zLbxLpGrQrBBdoJXXb5LLtL", - "H06c042iibO3v1xWiaZDgr3Pyn0z4PfFa3udRtz4Q1I3V3pcsJhdlhQ5cASOdxVyATjnIzmiv1Rk", - "hxfLhWP7sjpnvRScENxR+UHj8fuvDg5408dKf4/z9k8ILzxpifzFVfiDcFP+EdzbXM7HTQVEKgDP", - "uSeKZ8SLfWJovBrWU1nbj+yo/OEyljnI6YoUHp6lOSubXxABb4h+Flx0sbfr9RXUXKE/tQMcE4eD", - "/wBBriviHbavJ8VvCjWl1ZxwLZWwlV4ySx3DOK39TfVYv2wLfyrq0FhJPAHiaEl8bezZ/pUxg9Pm", - "O53/AIZt1uv2gb2BzhJZZEJ9ASBXe/FDVor3xJrmm2ZH2DSrOGygAPAC4zXm/giDWLj4xeNNXee3", - "Om6WznKQkMCzYUE5weh7Vz0PiM6j4Y8YapIhyJlYlm+9lqn2bshNnTaUpPhzQBgH/ibrx+Ir6evP", - "+SqagvXFjB/6E9fJ+iavbyeCfDFzKwgaXWhHGoG7ccj34r6suW/4uzqXJGLG3/m9RWTRUTJ8VhQs", - "Kjn5Ca2/htbNH4DMslrcuheUgqy4IJOcgkVgeLH/ANV3+Q9K2vhzds3g+CCaKJl3PtbH3huPBGev", - "pWmCjedjOo7Js+afjVPfDWWm1pNa0GORS2larbQrLDLCeVVlYbWx7EMO+a+R59U8YadqBu4Nd0rx", - "BBn/AI93QIWH+4VX/wAdJr9cdb0W/utImg1Lzxou0tMuowbkI+hGOnAAFfMfiL4I+EtW0m51GHTb", - "KxmKmSNY4pLYlB/EwBGzPYEE+1fX18srpWpyvE8/D5lQ+3Hlf3nyWPGHhq/09F8aeDbqwwdgu4Yv", - "Mjz9eCPpk1nanpfgFIVntNYu9OjflEuYnjz9N6ivbNR+HDWXh+y063uLix0i3uBes74kEs4OQGyP", - "mUfQcYrx7Wvhh4t1bUJrq2ddYE828siOw3E9cHPNeHUy/E05+4mevTzKhUi+Zr5nmmot4Zt0do9a", - "mu8dFhizn8elctHvubmFo7dpLOaXylw2X3dvpXslv8C/EzuEvpbe0fzdkyCE/u88qc4wc+3TpXpl", - "n8G9A0bwReTS6k019ZCO8kkcApkHPlgDuV9K6KWEr3978Tnq4qlpy/geHeEPDmrav4gewYyra25H", - "2lmXZn0U+vTNfQFrpVnpcIgtkVmxhnx1NS6DqXhe40W7fQJg87PvuYRC6NETwAcitSeyki8FTawj", - "oyif7OqhssrEZzivlc1xD9o09kfd5DgFNU4Racp/1+B3HgnxB4O8PR3Mes3erW2qO4/ewWwlhVfQ", - "87s/QV7JZeIPCmtTQxWvirQZZd4WFZZXtmJP8OJFXJ7Dmvjry1WELkuxUsxCnJP410+2zTUNKEcB", - "SdbqN94lJBGVONn175715kcZJaWPvsb4e4KtH2inJP8AC6R9rTaHqtl89zpt0g6BxEZAQPpkVWVd", - "+I2Z0l/hyOfYc817nE7TqY3U4UAMMkEt1qy9kl7+7njimXGSjqGz7ZPT617v1fqmfhrlZ2PH9EtT", - "B4v02Q4XdcDAzyeDXspzkHmsf/hHNGTUkvYYGtrmFsgJIQDjsV6Vo78AHPFa0oOCdzOTuMlJEwOM", - "5zRTXLGQEdMc0Vo1cR+P3xK+0mfwx5d5cQ/8SxdwQ43c1c+JQlkbwaBdXMZGkx7tj4zyOtUfiU5F", - "z4Y9P7NXn8asfE2Xy7jweoB/5BMX860h9n1Bs0/iDFv+L/hYmadAtna4CyEA/N3rS1aGNv21LOXz", - "JNy3UPAkOPuelZPj6Uj40+F0AyPslrkn6itPVAT+2pZMM83UQPP+xSjuvmB9H6Tp0HhT9nfWppUC", - "al4s1u6uSWOSYYwVX6AnmvlfQrO3i+CHjSJgWWSaLeCx5+avob4j+J4dQ+N2j+HLEgWek+HXLIh4", - "DsuT+PWvn/RyW+Cfi5iSSZ4v51EFe7fkK9kbmlWdqnwv+H8YiQIPFAZFx907hX21ctn4t6p1P+hW", - "/X6yV8T6dID8P/h2oP3/ABKD/wCPrX2hcPn4v6vjPFnb/wA5KyxK1+bNE0ZniogvCMZGw5rZ+GN1", - "Yv4SgWW3nKxzSFpWwFTDnJ9cCsLxW2DCR/cNXPh9d+T4Gn81XeAtJnYMfxnP6V05RDnxMY97HNjJ", - "8tKT8j1/XkDajbaZaxXFxBDH5jtNwm4sSOTxisqdbZrQ2cUUOoys4aZYocoW92PWrdqH1fVIoY7t", - "jbeWrhpLVnPsPQY96f4gk1k6THpmhi7h+f8A0i+3RRkD0Udvrj8K/R6snBtHylJJq5y2s6bpiBbj", - "VLKwV8fdeMEAfjXiPjr4neHPDNnLDZQpc3CKdkFrHkr78cCvWrvwJpk9v52qnVdauuS8l3fSBPwG", - "Rn8hXxh8Z/GGkeFTdaZo9pp8bsSkiwxkkn0Ld/xNeXXxMoK97HfSpKTsc/B498X/ABF8ZRaR4d0p", - "W1CSTzGPmnYgxwW7ADqSa+ivD/ho+AvAUp1e7Or65cZaacDCIcdEH9TWZ8IE0LwD8MPCizyWjeKP", - "FF3FJN9lh85grj5U+XnaF6nsTzXoXxBjifxDJZW8iMRGZGCsMD/CvhM1zKrVbinp+Z+nZJk1LDQU", - "5K8/yPm6FIX8V6jpbwrbnUrwXccsa4Byu1lJHfIBGfU12XiHw5b6X8H5DM5h063uluLyYKWaKLo7", - "DuSMg/hWfpVgbn4x28kluZRBEpyWAUHJ5r6A1TRU1XwNqem+UpW9sJYMHkZdCo/Uiu7C5fHE4T39", - "bo8GWb1MBmPtqO8X+Z8bardeC1gtz4c8XjXJZXKNbTQmF1GODySDn0rovscEWm6fJBdwyiOWNiu/", - "kcjIz2/+tXyj4ftms/iDa2kkMkVwt35UwZ84ZWwf1r1+2iu/+EinklnH2WQAQwBMFWydzZx04r5b", - "McHCjUVmfunCOf4nM8FKU47O2nofrPB4x8NmBYofEHh5psgKE1GMk+33s5NdGZZZLQRW5aKU8klD", - "hT1ya/HrT7eODWdMuWeUXBvEwhUeWw3qQV7k+ua/YC3nZrrymLlmA3M2AB+Feth6/tEfkXEeQ/2b", - "OHvX5r9Ow+Ka7KL9pijDt8pZASH9xnvQ2crgELu6Adq0Li2j+zl4GTZHjcmSefUf1rMLEdc/jXRs", - "fNB39j70VG3OTyfpxRRdAfj98THIm8L4wf8AiVrmrfxOBN54N6DOlRfzql8SBmfwupKjOmAZNX/i", - "Vj7T4ODEf8guLqfcVrDePqPqXPiD/wAlt8Nf9etp/wChV6b4b8LHxJ+2lrt06sbTR9Pa9lbsCEAQ", - "fmf0rzPx+R/wu7w4Mrn7La4/76r6p0qGPwp8NvG/iWXEV74j1iDTrUngmJFXdj2JJqHK0b+oPQ+a", - "NIvZ7/8AaX8YXMzZ221xGvsFAA/lWZopB+BHis8k/aIfx5qbwu+74+eMDuGTBdEg1T0KZf8AhQXi", - "1lYEC6hycj1px0XyQuh0unY/4Qn4aqc5PiX/ANnWvs6U/wDF3tY4x/oVt/OSvi/THD+DfheQwwfE", - "uc5/21r7LlfPxg1rsfsVt0+r1jif8yomf4pOTBxn5DWj4GlSH4dyJeWyJDcGQh2kxkbsf0rM8St8", - "0Gf7hrovCZsJfhXFbPFcYYOwZX+4dxyOfzxTwM3CfMt1/mZ1oKUGn1PQvDFzFqNvbWLyxiaKPZl2", - "IDrnivQptKSGBEW0jgUHP7kcH8e9eDxeZpfiW0liLNAThWYEZ9RXtP2gtp8FxHungZcn5uV9q/S8", - "TNVKUK0dpI+Qw0XCcqct0cX4qd/7Nl0+yDx3Mw27kXLKPWvzE/aQ0mS01p7SwjAs9NKveS4y0sjn", - "HJ9sj86/UPV7hjM8kcRR8cE8nOK+NPir4POrfDDxr8u6+lsHl3EZO8HcP5V4uJjzpnq0JcjTPmLw", - "p8dL3TPHejavqmj2ssGm6QNN06CwG1oHKhRKAT8zHGD+lddpnxP1DxX4nv7fS7C/EwyJrid/mJP8", - "O0c//qr5Te0vmhtbZFEmGJVkHzIeMgnrX2T8APC1lLayrdq81wzh5SWI3k+vrXgUsthWnex9LUzm", - "vThbm3PYfh/pN3F5l5qLq90w53ncx/4CuSBXaa23iC+065TTXlhlMLrbtHbOEjfadpIOM84r2fQt", - "AtrDTQba0jibbxsUDisO9imh8ShMbYpMsSexHX8xXs+wcYqHQ+fnW525Pc/J+30S/wBH8dabPqM3", - "mTNfhJDyWL55zn3zXs8+hajZWyXk0MfkocsVcnOScHHtmvLfiQdQ0b41+LLGe/JdNWklhVFKNEjE", - "so/JgcisBvEesvKc69cS28mNsKyvmMk55JPPpXyOZ5dKtO6drH6jwhxbDLaLoyg5czvp6WPoaPwl", - "en4d2XiNb6xaHzo3FmJh9ob5guSnqMfliv1Bgje4so4nh84FAS7HDA471+QMMEiajY3bXcgYyBXt", - "mUbTym1lfOSeTkY4x71+u9nOYdOS5kdyERSQAQcYHaufCRSbsbcczqTdJz/vfobCRG00wwBwuP4c", - "8t3GKphydvDD61ameCay3D5pBgq+cn6fSs4tg9h611s/Pyfcxzjk9+KKrkuXBxxzzmiqTA+aNO/Z", - "y+EnjjXrvTfFOta9bXulXbWNhHBeRxtJEuMFsocn6Yrdsf2W/ht46TUZde1DxFbpoN01jZyQXUa/", - "uo8EF8oQT6nis2x1q0k8Qa7LJe+GlhkuZbgXc8q+eMY2tEc5Iz74r07wDf8AhfVfD2s2HiLXHmku", - "LtpmtI9VW3SZNozIVDAkfiRXzWXZni69epCUbJJNHq5jgaOHw9Kqql3LdXTPnnxt8FPAeo/CfW/i", - "Curao/iPw5dRwRW4mjMMkKyhULDG4Eg/eziua+KPimC41f4Y+E4hvWGX7RIFbAEhJwT619Z6JoOg", - "618APFegWsVsrvqRa5zIpZoEkDIDzkjC9TxX54+Jbh5/2w7OJiPLguI0jGegwTX0FJtuzPKTTemx", - "leFUsB8ePF5js3S4Nvdea5kzu9eMVV0Gz06L4A+LUW0KwtdQtJGXzk54q14VbPx98XDji3uu9UtE", - "cH4AeLmAJH2iE4/Gujmuvkgex1Gi2lrN4N+GMNvYTTCPxCXiRDkoQwJY8dua+wpDn4y62OT/AKFb", - "E4+slfIfhfV7nR/Dvwyv7FY2mOvSQ4cZG2QhW/Q8V9bs/wDxeXWsY/48Lb+clZYr9WOO5V8T9Yf9", - "w1tfDK0kn0K3V7xAhkkzkkqoDHHGOtc74rkwIGHXY1a3w31Fh4LEUEMORJKpJJDBix596zwr1YSP", - "SvElo9z4ekePyHNu2+Nkbk461a8Oa/JLoMMccMsrlOVA3DI7Gudsb97TzLO6nR7eZto3rySeeKp6", - "XcT6Jqz7lY6e0w3kfwAnAP51+j5Detl0o31iz5TM2qeNT7o63Wb+UxeYbG8ibGH/AHLHFeOeItO1", - "O/0++i+wypHPHsbzSEBH86961SW4fQWkybiEgFXX72M1zWpWrXOmMF+YY79RXJKDu0dKkrKx+MPi", - "vQ7vwp8VL/T2TH2W8Zo1HRkJ3L9eDj8K+yfgRewHVoJ4NpDxgmPruU9fxBryv9pvQJNG8fabq0cO", - "9bq2KuVH8SOeP++WH5Vz3wD8XG08drYTSfYpA6yWhl4V2zgp+PpXJlslDEOm+p2Yu86Cn2P2B0mG", - "GfTUeJgyFcgt/I1yfiXTZHSVYV/eHByTVzwzrMK6VFMf3OR+8i/un29RXamyTUbYz8HA6+tddZWn", - "Y44O8T8e/wBpHQdRsf2ldW1eS0MGnXsUPkzsvDMIgGGcdQVNeUXng/xFpOmJql/p7QWQZMyMP73T", - "j3r71/a/0OMfDHRLuCB7uZNXCMqRlsBo264+lfEAtvHWsStaroHiG/08qCrR6fI65B4HC9a8DG0a", - "iqtRPbwOIioxk+h6fb6Vfz+HILwJGYRslRI1yzjjtjrx261+r9pIJ9JtpYkAVoFOd2D90YJ9K/HS", - "90nxz4W1DQLrXvt+kwTzQ/Z7acskg+dcN146dMd6/YINPbkYykW3+Igqp78+leLDCui3dn1OfZ9D", - "MuRxjblv17l2QyqVV8DjGd2c/jiq5yHGcdehpZXnfQJ1hkWW7K5TIJAPUE+3tVmz8G+L30My6jde", - "HLS9mVPs5ht5HAckZDbj0xnp3Aps+dSKgceYFPU9KKzb3wx4xi+IcGif8JNYRRLEkk80OmKSoZjk", - "DceDgUUrt9B8vmeCaL4G0nVrvWXk0jxXdrDcNCn2OSCRoVwPvA/x/wC0vFami+FLS71TUornSvF+", - "oWMFw8QjhsoXkVihUeZK3zBgGJKg4PFY/hrx/wDAzw7Prba94mfSbXUZSNNLwXBMltwQflHBz681", - "t6V8Qfgzpunaja+IfGkGlWF3f/a9I80XA8+LGFcYBx1781KTTTsefUoyaafkTadc2fgf9nnx7rga", - "/W6mxaLJcIFPy5RV653ckketfCt/cGT9rvT2Zsl5oTz/ALlfWfjTxb4Mi+Amu6VqOtW8aXf2mbSU", - "cMz3krECHHGc4JbJr48viU/a70n3ng4/4BVQd5/I7qcLKxf8KHH7Q/jAZ4MN3xU2h6JrsP7P/iSG", - "TSNRjuLqWFrSJrdg84B6ovVuPQVU8Js3/DS/i9ef9Td45ro/EU+oaPe6fqbzSQzpCssUkTZbBjHI", - "969PAYSNZNydkkjkxmKdJxUVdsv6L4W8Ut4I+HS/8I/rG+18QmW5VrZlMUe8Hc2RwMd6+tpEcfFT", - "Vb0eWtlJZwJHKXAVmUvkde2RXx9Fr2vX+iaBfSeINVMGq6kLJAHwYzuA3Hn3r2AfDSY+O73R7zxX", - "rM4gtopjKhxu3lhjBzjGP1ravh8uXxVH16GMauNe0EvmeneIY0vFTyruwARSGL3KjH60vhi+0bQf", - "B81pqOqaMlwzOw23OR8xJySPrXl2rfDTR9NWMtqWsXhcHPmzY/kK3/BPw38Iap4fF7qFlc3UivIr", - "Ri6YD5SQO9ZUf7Njfl5mN/Xn1SOm/wCEh8KwXcclz4qsXVDnarFue1b1n4t028h+zvdxy2tw48uZ", - "WwrDPBrAj8HeDLbU/s8XhrT5AeWaQs20Drzkj/69N1/wfZXumomjNDp0kQCpEiYjx6EDkdeor3Mr", - "zXC4ZuMU0n8zgxuX4islKTTse/Wfnf8ACMNEd08GRjDckeorQnVFt5QiscLyG615b8N7nW9Kso9L", - "1i4ttRjgulIKSlzsOcA5weCK9p1R7a4gNx8se8HOTXo4ipCcueDumc9KEorlluj4i/aF0zRrjRND", - "vtcsvtmk2usRfbYkmMRaKQFD845Xkqc+1eDx658A9GuY5LPwtoD3EbAo8urXM7Ag8Hhute4/tNXf", - "2f4I6rt8uVGmhXg9P3o5r4DXwxqbYuIrKEQyjfE0kqjcp5B5NeFVx0aNR3S+Z7OFyyti42hzO3Y/", - "Un4M/EfQ/G/ha9tbSRBJp8oRcBvlQjKjLckDBFfQaa9LBpT21uQyjJYg4r8wP2eNUvfDXxIvtGvS", - "ijUIhIu1w2CpPcfWvvaz1DdYAmROWKn5q7lX9tBTXU5amGeHqOnLS3cr6tqcx1C7aRsSSL+6ZugP", - "b6fWvkT4o+M/Hvh62Oo6TqN9daR5nk3ImmkV7SQ5wCoP3Tjg5/pX1Brd5Ap2kCQgEYXmvJ/EkkGr", - "+DNU8P39hFe6fexmKWcJiSPP3drexwc+1VRq3Tg3Z9PU5qtOKkpWufNPjI67rHhzTNSvruW9+yyQ", - "XbNI2diuFOOc9zX6sWrzmKF5G3AKD1wBwOxr8q/isl1oeg6NZBhEEighuVBGGKxY/EZFfbekeNte", - "bQLDckKxvax4eb5mJ2DIz9DXhZ1+7r2f9aHpZVLnw6fqfRw1i0Fm8F5NsiJxJJH8rbT1I9MDJH0p", - "dW8SeAIdK+1Q6t8Q9VX5oYX3TeSZNnY8fMAdw/CvMPhtPca98d9CjvpTOhmZmTGUIRGIyPqK+0JL", - "W1bWSv2a38qKItt2DGTxn68V5MW5q6PSdkfMdrNo2la1pd1pFx4kurnVNOMsh1m4d5YwMgZDeuCc", - "0VXfRrvWPE1/4kt9QtrSOGSUYnjLJ5YZjxgjHBNFUtBNHwL4s/Z48aazpegxWuseGxJZWvlTb5pM", - "FvbC1neMfg14pvNS8CwSnSjp1mkVtqVx9sCCNN67nAbGVAzR4h1XUg8mL++jOMkC4bj9a8wjuJ7j", - "xGguLmeUM+D5khb+ZriWOjfS5+x43gLCRjo9zo/i3YXOofFfTbXw81nqGh6cAqzR3abRh8Zzn0FZ", - "d9aTXH7SGn69BLavpUTwtJOJxkbVwfl6muiv7fQdJkt5dStmv7N/lVLYsjhvruxir94vgO2tYrq/", - "sdetw/3dk+4dM1wrM56WR7tLwmwUY3nUk+v9aHK6JFFpfxt1/XLu7txZ3aziJRu3nf04IArsPiFY", - "XNzpmkWdlE094+noqRqwG5tg7k4rMW80ttKeTTbBExIPLaXDHZzy3GSfxrqfHUxGqaLcxMAxtlOQ", - "vAOz0r6jIMTUnhsQ30iv1Pzbj3g/L8vx+X06Tfvzs9emmxzmkeG9dj+HngmGbTJoprTX/PuUZ0/d", - "R71O84OMda+nrjVtMj+MOrXj6jYraPYQIsvnLtLBnyM568ivkk6jfSOwa4ORjoij+lMF1etcEfaL", - "hsrk4Yivm6mPlLdH2c/DXAJ+7Vl+B9Q+KNf0i5hhNrqNtPs3BtpJwfyrC8A+K/EGm2V3HDBaSWD3", - "Eux3djwSecYr57xK8ZLO4YHgu3X869I8HajGvhc27fMcurKvI/EjpWmFxEnNo+Y4r4Qw+WYSNajJ", - "t3s726nrR8dPBAyJYqjMf9eMHJ64BNS6LqOs+IvFkGmWk8VpLLuLSoN3lqBliR647eteZMDuVSF2", - "febI4T0Fd98J5Fk+MRSSV4UNnIY5QeN2Rz+Wa9zLqXtsTCnJ6Nn5ni6jp0JSW6PpjwJ4Q0/SdNmv", - "rs3sGY/MnmnXkk9MngLx2HrVDxDrMOoTXEuliRNItEPnXkhxGD6A9z7DmunvdT8LWXh9J/EJvtTu", - "v+Wds12TET68cV4N4w8RTayQ1y0dppcOfsthbDbFGPXA6n3r6vHzhF8lNWSPFw0ZtXnqeS+L/Eul", - "2tvdnXhZvpdzHJG32y3aZFOwsjbFBJOVHA7nnjNfO3j7xV4f8XeKdN1Hw3JMLC3gNs7S2vl5QOzo", - "qDqMK+3kAYAxXSfErV1vdXstMQAoswll3YwowQM+/Oa8c8L2F7q2oXeg6dHLqWqwyMzRQoSQqnae", - "w/2elfGZhX53KFr2P07hvBvC1MPiJu3PzL/I3PDt9eWnx/8ABzWm0rPPslGM5Qkgj8ua/QyKK3tP", - "DlkfKtWu5RuWMg7kHqRmvzbXzLP4q6FOsk1vdWEm9jGMHIcAj8c9a+7/AA/qP2qVSmZETA8yQ9fz", - "r3skXtMHZbny/F7Uc1qPp/wx3DiJ9OcXFp5rKPvAFQPwFeW+I75Fs2YbWA7A4Ar0fXdftrPw7cAC", - "JXZcZFfOGt62JkkRH3JkkYPFehDDuM0fOTqqUDzj4zedq/hHS9Rt4wxR9txgfcKKfmz2BGK+mtHv", - "p/8AhEtNeGBMGygdSSG3ZjUdP614EI7fU9DlsLiFZ1eYSbC2Qcdcj0xmvfdNjEGmW8WBBGmwRxjG", - "FA4AA+lfO59Nuuk97X/Q9vLcK44ONTo2192v6nunwZunt/2gPDslxEIzMXi2g9C0bc19n6peCz8N", - "a7qDHHkWrtn6IWr4Z+GV40fx58LxbSXF4HJwBhQrbmJ7ADv7V9f+M7uP/hTmpmKRJEvGWGN0bKsH", - "dV4PcYNcGH+E1nueD+Jr46J+zncxh9t1eRR2w9d0mAx/Ld+VFcZ8UtREsGhaUhwnmvcOAeyjav8A", - "6EaKu9iT4b8Qffbqa84iZR4jjBOPn59q9G8QH527DH5V5rGFPiKIsCBu5r56D9+5/UeYp+zsd3qo", - "0jT47a7uYotYtmYK1vGyrhuzEjmtfV7/AMNR6Lbtq/h67liCkxCG6I/h+tc9qt7pWlxQ3kUMeqpk", - "LJazMAmf7x4zW3q3iLSY9BtpNT8N2t3G33EjmIx8vNS6tJv4T6KnCtGi1zmHFPb3GlmSytvstu8T", - "bImYnBVu5z712Xjdi9toLIRua2UZHP8ABXHwSLe6FHfW0AsrUXJRYVOdgYHFdD4ynNt4e0S6cSOq", - "W6swAyxAX+dfU8OP9ziV/dPxbxUfLjssm5fb/wAjjAs63RzJIqlckjCiiTakscks/wC7ORkyZ5/C", - "uXk1jy9PNzBYyzW9wQSSf9WuerZ+tSSXt7FdWsDxRpYPkLcA4O7rj2FfMKEj9G9tTuk32R2KCAXf", - "kvjc+MYUkc+9dX4RJSPVyDNapH84keMY6dRmvKrWTVJNflt7+eNJchrR1HAUg8cdTXtXgLSNcuvC", - "d+TZ3N5G9wUMiAPjgHk54+mK9TKstxGJxChSjd9j4LxEzjC4fJpzqaK61fe/5ma3iE287fuZXYqT", - "vlfrn2xXffC/V3uvifHvWNLd4JVG3OSQmeMnnpXPy+HoU1CZZ7Wa7cE5ViASfoMn9a63wdpw074g", - "2Ev2KeBPKkCs0bAJmNh34r9Cy/hHH06katSKSjrufzViOLcBUXsoNty0Wmh6J4g1RWtxMk10wiXY", - "Vkk6kcdO3GKpaW8Or+Gb4z2waSJCVYnvXJa3eT3F9LbRHKykO2MEkf0rovDXm2mj3m/LBo29+1dF", - "bAc8pM3p4vlsj4d8beJdSm+M2v6dbWMEkdrP5fIOdqgc9elcDBrmqeG/iPdapZ3baTczrsklgO7y", - "w4G7gH1A4r2T4yeGPBFp8M5/FCTzxeL9Qv1aOLzmZJQrYc7ei4UDn1r52037DcXSJN5hbPz+Y33v", - "8K+dxmWrDVEmldq59Lgs9rYzDpcz5YOyv5aaHTajr0N4lxKl/dXNx5YV7p/4yTknZj5efc19IeFP", - "F19J4J02azuMSNAm8EdWxg8dua+erjw7bS2ZmtX8uUxbApGQ3Oc4x/LNdv4Wj1HTfBNo13G0Sh3E", - "T4+VwG5we+M4Nd2UydOo47Jo4czvUipSd2e5ah4kutXso7S6m8l0BBVejGuTuYXijDMf3eeD1zmo", - "4pY7qGNwTu7gVp3dk1t4OFxPK376ZUhix75zXuune7R43NYm0uBoo/NI/dqdx9MV4bd/FfxTeQeI", - "rBL+cJfX263aNGzGin/VxtwVHT8j619E29pMmhs5yuIzuHZuOlfLsunCxW4eTYtqkjtCfNTK891B", - "JHWsK2VKpUVSSVrW/U9HDY//AGf2S3vf8Ev0PRdH+Knif/hObfX47y90y8h0xtPu7pFHzISR90nh", - "tpI3Y719OfC39pLV5fh38O/h1qtlpsfh+3llR71XZp41V3+zxFc9FZlXODkAelfF2nXEFvqUUt1C", - "ptsK8oZsb1z1/Sut8LwwXPxR0eKKaG1t2lRxJcSpGsab8l3JwQAOSScccV5udU6WHw6hFI9LK4e3", - "xEVN6NpH3Z421ZbjxtqM7sTDYQ+USTwNo3N+pP5UVasfh/8ABrxLf6lqS/FC5vJ2k869MervHCWk", - "JOAhwCDhsAZ4FFfJKLavY9GeDrxk04P7mfKGvMJCzL0Oa84TB19OT9/mvS/EXMjcY4rzMf8AIcTv", - "83NfO09Kh/TWaX9kzs9T1G00+yivrCGO8kjIWWGcOU574PBOa1tW1/7JodtPeaLo9/E4OI3jAx8p", - "PpXH6lPPZRxXukWF09/GcAPbMykH0GcE1019r+tW/hdry4tbW5KQhjBLa4ycdOlXOvFPWJ6NCUnT", - "lr06GXbuut2lkzxJZWrs58mI7UUjOK6nxJcXOleH/D17DHK0lvAGiC4O7C9q4i2kbVfB66leLFal", - "b7mL7qgMD0HpXo3idxa/D7wpLHbpepFaoRCHKiQBfu5HIzX1nDtT93iEl0PxjxTgnVwE3rea/Q8N", - "a8nS0kmtbNDaXRLTRsxxApPOPXrT3MieVE8kb6XyFwuWD9ck+naod97PZXF7ZW8FskjF57flvLXP", - "KLnnjnn2qRrWaNLW5Wd3sSxRoAOAeu73r55Sm3oj7+NOmkk32LMEMsepeTe3Es/mHfHKxwVUj7ue", - "1ey/De0tLfTNRuLnXYIEeQiKJJpBg+pxx6V47YWNvHrkscTS6jbyEM3lkysjd1wue+OK9/8Ahxo+", - "oQaDfwaj4W1CC2actHcX1wLZSmMDAYZ/SvsOB4NZrGVR6JP8j8n8Ya8Hw9OlTtzScfN7/wBajbTU", - "J41ljOlWuqW6lxHeMGLSrnnJwe/p1rq/By+Ip5yJdaU2EkuLWwS4QbIyMbduAR171nrouj6MZJdR", - "+ICaZaFmZLCx/ftGM5wCwx+nWt/4eW/gl/H0kXhzTNZ1C7k33E2qX52pFhcbgAAMnPHua/Yp5hhk", - "+W7P5aw+U4htSta1vM6a78MWun26XVy0LOsZPU5OTwKnjiEemysoKq0RZh0xxXZ6hYWay+ZITMRC", - "AARkKenWuS1i8isPB+q3ox5ccDAk8ZJHFeFOlGCZ9dGrzNH5sfFK9ubrxyLaR5JI4wyQqeylycD8", - "Sa5nwz4e1HW7mZbDTWv3RMuI5wjr0GRng/Q113jBPP8AEmn30mDtaYn8BuFaPwqv5bTxBqdrbzQw", - "XFzb5jeRQQcfeH45/SvgoUFiMb7OTsmz66tXlh8E5wV2kVNMaeC7fT7xJVlU7QJU2upHZlPce+RX", - "UK91ZrEZjLLaEsSpJKKCRkgkhfrtFYPji8uf+Fm+bO6zXksgjnIxjdwO3HpW1ZT/AGuwbKv9qAIL", - "CISOfxbhR+orFydGq4p/C2vuZ2ypc1OLktWk/vVzutHtiZ4mglRoGwcZ6fT1r0pdKbVNbtDIirp9", - "omACeGY9TXiOl6m1jcCOSTe4Py7JhIwz6kcV7P4f1X7RorJJcQxQKCzvPIAAvr/k19VhcXSnBP7z", - "5zEYerGRoakcw3EcZQRW8W7C9Cdw4/LNfI2o2GmjV9ft47tLuG4mLSTplQpPoGHY8fhX21oegWvi", - "HWP7La+g02G7IihvrrCIZCfuYJB57HgZFbmt/seWmn61G2oeLnt7q6G/yokhIAHGcLwAf1roqZph", - "40Epu7u/krJF4bB1Yzb8kfEEkekxWOgibTzeSTTC3jVnPyqFJ3jpz6A8V1PhLw/qvivxpp/hPSLO", - "4Op3NjuSSU7YAMY54yD36/hX2t4d/ZY8M2k9s+r30/iFIJxNbrMDEsbYxnCHnPucV9Q+G/CmheGd", - "IisNJ0mxsYEXCpDGB/8AX/OvmMxq08TJqKPfwVaeGnGa3Wp8QeE/2cPiVaXk63Umh2iyw7UuGk87", - "Z77AATxnvRX6GLHIQBFCE9+lFfO/2RBdWfU1uNMyqSvzJH5Q+IB87V5iP+Q9H/vj+deoeIOWbvj2", - "rzDgeIIjz/rB/OvmaK/eo/oPN21RlbsevXWl682m2sug6LImsBP9HePyneTPZRnOe/StvUbb4kaZ", - "oFtN/ZGqT3BwJY5NOL9j6D1rdn8fW9z4Ys7DSBFpevRxqLaeNiJGwMELlf613upeKtfsfAVlPpWu", - "Xc+qfKJ4ztkx8pz29cV+s0uE8nrU7xxdnppo/wDI/ner4rcZYSbhPK21qrpTXo9LrY+YNRMz6Mbz", - "xRtsNSa4Rhb3EflEghgSFPOBXXeIg0vwv8KLYNAzvbols7nCEkYGfaud+JUl3qbaJq+sTNNqky4f", - "cgBbG7OAPrWj4jdm+BXhY2+MiBFTtzk14uX4anhsViaKd4xW/ddzr4yzXEZhl+XYiUeScmnbs+2v", - "mYieC9PshFNrvjS0092O67ttOg8wyHuu5ug/CtmJvhvpV39qsPD+oa5c7dok1C6YQ49dg2rXjkc+", - "p3Wn3PlvFp9zDyfLjBLHPTc2TziopoPtcNnPLNJJqOTlXcksufeuKOOwdJfuqF356nZUyrPcW74r", - "GcifSOh7IvxQNvFJY6BDoehojkGLTbUbge+SoAz9TWFN4ov9SdJb271K6aWYoQ8+0HAJzhf8a5PS", - "rD7b4xH2G1lSRRtdCmNxA6genvWvq0cekzac00YhZ7nywqrjJOR0/rWmIx2ZPDyqQXLFO2isYZfk", - "XDsMbChWn7WpJXV3dW7/APAPsD4Z/CbQfFPw7/tt5obOccMMAt90HOWz6/pXR+E/C9jovxr1Dw/D", - "11DTJ4baSRxlLhoi8LHaccSIv515j4Uv57fwNpzQMoV4FyHRW6fUHFdXouqNb+P9G1G4ljiEF5E7", - "uqBAqhwSTjHav0TC5fiJUufmXK4bdb232/U/CswzPAQr+zpxftI1Hd9LXatuWL3xJ/bfw00XXb7U", - "zpdneQC4+z21v1c5DEt3IYEe2K8b8b+LoJvDR06xury4R/mZpLcorD39axfEXxMvPh54ev8A4V6j", - "o8c2saV4kuDFqE4zELSSTegVepDBtwPTBFcV448Tyaxozpoc32rUVTeqWNvvwAOc7Vwo/Gvnqmcu", - "VHXc+njlSU7x2PE/F8oGuWNqDlvKkdyR3YYA/KsvQpY7XUrK5Z3hiDeXMyDkAjHFdZ4ltF8Qx6Vq", - "WjyW9/OqKlyiNsZJMZKsGA5688g1lJ4W1+08J3F9e6ZeW2nOxW2u3jPlOyMMgN0OAefTNfO1puOI", - "bi72Paw6UqSU1a+6NpPDeoa741tHh0bU72z84l5baPac54wx+Xr6nFRAy2XjrV7G4iSExTbmjL71", - "UNzg46nmvWvCXjHVr/4f33hOPw42ua5JF5aPaAM1upGAdwJCj5unTOM81xGn/DvxtrvivVbnSdBe", - "UWQxqqllD2x3EAHuTlTwAeBXDCqlJK9z3Mbh5TUq0rLay62tuUJrSS6eKCOSa2aSbdDKwEUStwAV", - "Ucn6V29ovjvwJq0cutaDb+INI/ju9JTzCv8AvKK88MjhisUaeceCFgMknXoCeFPvX07H4U+K/wAU", - "Pgx4O1P4fI1heaEk0LqwSyjnUlQpRwuJD8vO4nnNdTk17yZ5GnU8T8MePLrW/G17YarqFloVleTO", - "yzzRlzAD/B1H5k/4V9T/AA98e+GvBnjnRvD+n+KtW8ZxancLFLp0f+lmIsf9cpA/dqpPK5xgfjVP", - "4ZaBr3inx7qPhH4i/Cnwz4k1XT4xJcX93HBasq5CkfKrF8Mcbh1619T6X8MVsbQ2Wi6B4S8Bac7D", - "zW0m3EtzIvpu2Ko+rb/pVSr1Vpy/joSo05K6Z6lFaQbFeNVMZGQyng+9XI1RASqn61Da20NpZQ2c", - "KylIkCIWfJwBjk96vC2dmztPuc10cysYuOpESzHjOfrRVuKyCqfmc5H1opOoPk8j8jtfHL54HNeX", - "S5GuIT/fH869S17ln715ZdfLqyE/3x/Ovgqd/aI/q7NdaTO41WLUL7w6be3YQS8GORXIYVUvDrVn", - "4ShWxvrtLtNvmMsx6d+tehweHtYT4f2/iKXTbhdFlfyY7wr+7Z8fdrGvoV/seQgDIAz+dObmmz0M", - "NTpVaCcXfSxmSwXF78J/Ds12ZLrVYbyVJS3zMRtya1deheb4KeHYYGMUjFERiPuncQKls/EGh6Z4", - "Pltb5pft39oPIiJEWBj2YPPQcmq3iu8W9+B+kXFlHLBGx/dk8MuHIB9q/Tsqo4T6n7ZTvOUfeWnQ", - "/lfjrE5qsylhZ0eWlCp7krPVvXf5nDWHhi3n0e+Gq3Yt76M4iLSBRJID+vTpWvHb6FI9roeT/wAJ", - "Bar9omIjPEfoT0P0ridU1W31GDTJwJE1OwwUEjk72GMtj39TWdc6/cXWstq0Ci0vkUiV4xt3+3HO", - "Kh5tleGfLTp81tL909X+JquGs/x/7zEV+S/vWXSS089OXV+p6rpeu3Gr38uraHpSRa4JvsUFrIwL", - "SE/KGI45OfwrjPF11Lb/ABMXTdZurPVvEcEqQzG0G5LfIyVyOPlyQT61xqapdw6hY6hDJJFdzT5f", - "ychuBnjvXrPg/wAH+IPFdy9wnhnWYIJFLLPIqRBn7Eluoz1xk14GZ5xXxyUbWXVLZvufR5VkeAyW", - "bk5pvo3q0nbReR9nfDr4c+H9V+B/hvUp5tSW4ntA8m26IGckcDHA9q6S7+ENlNHttNV1CENxhgr8", - "flWl8P8ASrnQ/hloukXabri2tlSUo+VDck49smvU7WSIIp8ps47CvUoZnjKcEo1GvmfnWPynAVcR", - "Ofs07tvY+R/ip8Dx4y0TTbKLUktviNpFsI9Ju7xQkWu2icrC7jgTR8gHrtxnjkee3XijxhpGlnSP", - "Efwq8WW+qLF5RW2tA9vMQMbhKPlIPrk1+gVzYWurWBtb6wivLViCUkXOD6g9Qfcc1TuvA+iap5Qv", - "rW4niThIHun2D2xn+tec3Vu9nc7IxhbsfHVv8MFvP2D38Zw6DaweO9LgmljjQPNujEpbydiffO07", - "R6EdeK+TtR+LGs+IPhLYeC7+ziXSbfUZLtYY5WEccki7XKKc7S46n2HFftBBpVva6QNPtra0gsli", - "MQt0XCbSMFcDtX47/GD4Z3Xw5/aP1zQo9j2TD+0LFo0CKYHJOAoJwFO5fX5c1TlKG/UIpNn1x8Kv", - "hv4a8MDSfFvg6Vriz16xjgsYZYw52eYokaYnO5twIOMYGAOTXudnon2fVLudYLHUbC8Z0vWe22yO", - "QQjs+D/DuHPX8q+V/wBn7x7ZaYdP8Na/cx22jTXLyWd7LNtWzLRnfHzwFLYcejA+tewa7+0D4X0S", - "bfpBl8Q6kL2dbuKJfLt5AwK7957kAcgdK6aOFdRe4rmWJxCpv32fnv480tNB+LfiTRzIjx22oTRq", - "PPZVChjtxjqMEfWvsX9lr4neGvC/wW17T/EutW9vHbXge1gjtnMkgI52jnIyPbFfG3jbV21n4maz", - "rIhhsjc3RkaKF9qpnsKXwKl7c+Irm3sLee4uZE4WJC7Nz155P1xinhqa9qoSZOIquNFzR+i/wX8T", - "WPi/9rb4ganp8c8VtJYZiEygNtM6kZAzjrX1qLQFPmZQB618EfA/QPG3gvxvrGuSpbWCX9mINrss", - "j8OrcjoOnrX1LF4n8Xn5nvdLePPAks/8DXpYjA1Ks+aG2x5mDx1KnBRluerx21t1DKG9aspCgGRI", - "h+hrzBPGOtrKqyabpFyccld8Y/rVtPGGqrMN2gWUqdzHekH9VrjeX1zuWYUO56gsSkAYyfRaK89P", - "jaVeTol7Eo67LhGorN4KqtyvrtJ7M/K3Xh8z85ryq/41Id/mr1fXs7nOOa8m1FiLzcOgPWvgqfxo", - "/rHNtKT9D7QEurXf7H+m6UjGa2toVumt1ZMKmSdx7556V4dcuH0Ob6d6+tPAHwQ8JeJ/gR4b1a4/", - "teG9vtPR55ILsqCT7YIqTW/2Z9Jt/Dt7dQeJtT0+yghaWZ7iBZQiKCSeMHpXq4zB15z5uU+LyXjX", - "K8HTnSqSad29uvyPgbXNStbe+WIwM00ZYuegO4DFdfqEy3P7O2kXC4A5OPQh+lenWfwa+FniTUxf", - "XHxdbyJQAIl05oCR/vNmofH3hHQPDdvpnhbwjdnXdKhlhzNGxkA3OC2T+Zr38gwVWlz88bXifm3i", - "DxTRzJ040ZXUZp7W2PlLTtE8R69rMx0bRL+6ZjgMkRCfmeK9g8N/s4+NdXKyapJHpdu5+YKu5v8A", - "Cv1A0fwJ4Ws9Og/s6TTHTYCvkyIe3tXTx+HYwP3UI29jxXHHL+V+8cmJ4lxNXSLsfGfgX9nvQ/DS", - "xTPFJf3a4JlnAbH09K+htP8ADsdpEiRwqOOMCvU4tDwcsAfwrSi0pEX/AFa8eldVOlGK0R4lStOp", - "K83dnBWujODkKUrfg0xgqlua6cWgUcZI9qJBFDC0spWONRl2c4C+5J6VqoNmbklqyjDbFVHyjFXV", - "QA4VBke1eHeNP2hvh34QaW2g1BvEuqJkfZdNwyqfRpPuj8M18j+NP2lfHfiZp7fSZU8K6Y2QUs2J", - "mI95Tz/3yBXo0cvqy1lovP8AyPPq5hShtqz738WfEHwZ4LtWk8R6/Z2MoGRbKd8zfRFya/P34/8A", - "xV0D4lLpR8P+Hpbe50m5MsGo3bASzIRhoyi/wn0JP614RcX1zfXzz3M09zcSNl3kYu7k+pOSTXY6", - "L4D8R62VZbX7Dbn/AJa3GQT9F6/yrrlgcPGFpas815hWnJW2OOsxJaWC61YW5vvDcz4u4VO57Jz1", - "VvRT2NQ3Wo+HYbT7VBrAZwvFokRaQt0VR9fU4xXtNz8I9f0Gx/tXwndfb9QXm80+ZV8q5Xr0PBPs", - "favn/Vmnk8TXpu9MGk37sS9r9lMPln0CnoOK8NOvh6jV7I9pOhiYK5yV7IfLcnIlLZYgnr1r6o/Z", - "R8PNdL4o8QyxuYg8dtFIQMMfvMPXjjvXztoXg/xJ468UQaP4a0ye8lLjz5whEEGeCzydABn6+ma/", - "TH4eeBbHwF8LNN8N2b+Y8QL3VxjDXMzcu+Ow4wPYCu7KqDqVudrRHHmuIjClyJ6s6+CCOIAAD246", - "1qRIOAy5GOMGmRR4bnJ5wCe1WOE2gbgB1z6V9W2tkfNRiOUKJi2f1wKlbYcAMoA9B1qiwUzM5O5w", - "vfoPfFMk5jyHYN14XOR9PWsE9zS12i60wDjLBVHbHWisZA3nMcsQeQD1opWYXPz31zlnOMZrybUx", - "+/YEDNeua5j5upHvXkuqY81+K/GKfxn9t5s/3TP2C+A0kUn7Jfgh2IJ/s4Djvgmtz4tagtj+zF47", - "uIQcjRZ0XHcshUD9a4z9nOfzf2PPBrZU7bdl+mGNWv2grqeD9krxWtuN1xOkUEYzgEtKo/lX3M7O", - "nbyP5ext1Xn6s+APB2lMbBfkZWMSb0JyEIXGBXb39jcW3ha7uLWEz3HkkpETjeccCqfgu2nTRZWu", - "UjSctlvLzjpivRCsX2eFZQWJO1Ttzg47+lfXKKjgvdXQ+CqSbxd5O+pzHhT+0JtBsJZw6X4twZER", - "ztXPfNdsuu6nap5Vlql9HM7hQ3nMAPXvV61gjjtwioqLtxwKsR2VqXLqis2euMmunDUEqSUtzlr1", - "5Oq5RZOfGvjGzlDweIb/AADjaz7gfzrbtvib48S0i2axHcZb5vPtk6deuKxp7Vbiy8kFUZjhT6VT", - "khktGZFQugjyxA4Hat5YShJO8UZxxuIhJWm7Hbf8Lp8VQpqCPHotx5MZKgREsMDOSAefpXiPjCPx", - "z8RrK2uNU8aamLK5jEq2CRCGBFPbYpGfxya3pfCNobfUbtYngv7lAplRiSvHQen+Na+m2a2umWNu", - "DMzR2ygyO2Tjpk+/FeBgqc5VnFx5bdvU9zHYpeyTjJv19P8AM+eZvg3rKI7R6pZ4AyPMjYZ/LOKq", - "Wfwe16S4R9Qv7OGzxu3QEux/A4Ar6sjtA0ocu0ik/MGOcii7tkTRp9oC4jwpFeg8G2/iZ50cU7ar", - "U8t8N+CvDmhvmO3Q3actNMCzn8e34V6XatpipCBdwDzuEGQN2fTP0rHWNZbXe6cnjcOuCDmuP8Qa", - "tH4f0fSb2WO6ngScRyzFOApyAc+pPH41w4iMcL70tV3PQwd8W1Fb32+X+Z7dC1uMCJ4A4AyGPOKs", - "S6TpeqoGvrDTL5SODNCsn8wa4j4KfH/SdG8fa/F4q09/Ef26ZViCwqzjA8tSxYY2qOAoxj8av+Lf", - "HmmQfEWz0uOaw0qx1C+aXTrZdMCrDGCSFkcE7sHjAGDmuGpmj9mpxpc8fVfr3PUjk0faOnOpyStf", - "r+h31na2lpZLb2sFva26/cjhiEaj8BxV5p1CkAqCBwx5NfLPjH4ox6P4mlfS75r9ZIRGq2TmBIpM", - "/eMbDjoBjiofDHxH8R69oV0sF6jasjny4ZdpULkfMeOw7d6dHO6cmoJcr7afoTWyOpSg6jd49/1P", - "qz7QSEDvkkdQKaJ2L5DZI46dM18w3Pxc1vSNUNvqNrDcRq6mSS1iLqF2kkEjGGyOhruNC+JR1e7m", - "X7KsCR2qTlpAysFbsfy/WrjmFOc1BS1Mp5dUhT52tO57IWYvlWXk8g8Y/wA+9RGbAbLqD/eboBXn", - "N/42bTtEe+nsHZF5CRZc9cdAOeuasN4t0+5t4t9vOI3IZWMYbnGRkV6NLmV7K7PNqShu3ZHcugEp", - "kU5LfeYHGfxorih4ks5mKPdTrjBG6IhT/n+tFUpye0RWhHeR8Z64MBvX3ryTVCPMOOuT2r17XgQH", - "9+9eQ6vxKcnvX43B2kf2xmaTps/UD9mvUGP7IfhxQAfLeVMk4/iNX/jpqH2j4KCyOGE99EDg+mT/", - "AEryP9nbxJa2/wCzlY6dJLGZUuJMoX5AJz0rp/i1dpPoOiwxsGWS6Z8ZzwFP+NffYOHNKDt2P5Yz", - "98s63q/zPLNDg8rT0B5JbJrrYlyOfwrn9PI2Kq447DtXRwjgdq+6aTp2Pzp6TNBDhR1xUw4iYRkK", - "Sc1y+veKdF8M6Kb3VbllUEhUhjMjsR2wOn41zdv8WfB8+l/aory9dB/rALVsx8Z+Y4xUvGYen7sp", - "JP1RtTwGJqR54wbXex67ArZy+DzlfaryqChyARnvXN+HvEGk+I9G+36Pdfa7bcV37SvIOD1rpl+6", - "K2U1ON07o55U5U58slZjJ1YpGqjJLc8+1MihVJCcckBcegFTk5HXvTPMG4DPTnOK5aNLlm2aVZtx", - "SCJj8+ehY4Aqvds4jiAVpQ8gUAJkKPU+g96sRMPKzz04p55SrqwlJaMUZxWtjFSz+dFkB8pYiOD3", - "5rhfiRHYW3wqkS5tZLi3M8YVVlKtnqMGvTyAFPY1l6jZRXsEUUgJAlVyPcEH+lcGcUZTwzj5HZlN", - "dUcRGZy3hzQ9PtYoZItJSwkjtogAWDFML93gc9eSe9UvFvhaHWfE3he9dXk+zXwWTamT5ZDEj/vr", - "HNehgbd2MDc3p1pWj3CPPZs1y/2VBYRU7dV+ZvHMqixLqX6M+fPHfguyuntmsri1069UyNI9wDvn", - "DMBnjrjtXQeBvhw+g+I9T1H7a0UE9oIUt1ycE9SxP0zj1JrtNa0VNW1q28xUFvA6bhtzuG7cR+YH", - "NdfbII4SehLGvEoZRF49ztZJntYjOqn1GNLmvda/eeMz6UbjQ9RWSd4pk1oDzIlx5nlQhc89iTWv", - "JYzW+oXmyadIBHFBvB5LmQfkBnFadxp9x/wha28MQ+1XOrea/bCG4Usf++RWtqlncmNY42LxfbrY", - "4/uqH3MffOBWUsMm+brZfqaRxaSUel3+hcs7OSezjeaQMd7Dp1G4gY/CmTWcax3M1v8AvjGxBBP3", - "cDPHrWhYM8WkRedG5ZIw7ELySc8YqCySWO41Mzbgsk2UO7OQR6fjX1tCcl7NLqtfkrnzFanBqpJ9", - "Hp82YwB1CynNsy+TjYCVwVOfm5659KKW1t7g21sw3xp86uHOCSrZH8qK46vNNp8z+R006ip6LT8T", - "5u18ZRjzxXi+t/K7Yx617ZrwOxgR0rxTXRzJxj0r8j6n9sY/WmbPgLxJqGn60kUNzIkK87B0r6i0", - "7XIfFVxG2q6l9nlt4wsUbjG0H618e+CgX8YRAAnPB5969I+JNlPbxWN5bSvbu427ozgnjua+2y3F", - "OlTjKWqR/M3E+H9riqsFpqfRGjW13ea3qM2kBb/TIm8sSFwhaQH5gAevXrW7DHrmpXt9pulWy2l3", - "b4Wa4uMFIWIBAAB+ZsHOO2ea+EPDvifxBp91PbWWuXttNuL7RLw3vivpX4eahrGqeEr+5/tzULbU", - "1vd11O7hkkDLxhccEY619FTx6+rJyk7PqlsfFVMA/rDUUrroz2G58G+Hr/UbLw7rK202pTo821jk", - "g/xSbQeBn14rwbxd4g0zTvEth8PvAukRW3hu3vnhv78APcX8yj5yT12A/nj04r1J7Pxrp73N3pus", - "2kl3foC11JEm75VIAU/3R1+teOPBc/CHxVaa9qtra6iuoQ8mM7pFYNli2R1Oc8V5V8FJtQVpS0u1", - "0+Z2xji6aXM24rou57z8N/DFr4Y8JfLPLNcXKKXDrjy+pwB2HP516YJBtHOK+dz8XtD8R3trb6pJ", - "qeg6ZGnmM1r8rSycbQxHO0DJx61ryeOvDcevaDDp/jK7ms7i5P2tLgKdsaqTjJGQScDP1r6HATp4", - "WgqUVdLqeNi6dXFV3Um9We5Fht68fSmDv3Nc3rPjXw1F4dWbSHgv9RuZFhs7f7SFUuxwCx7KOp9h", - "WI3iLWrLSru5vdKtruO0TNzJZ3YIXjJADDmut4ulCfLJ2ORYStKN0j0IYEQHenFsJ1qSysri40W1", - "uZCkEk0YdoWbJQnnaSOM1xEvjXw6mtXdm+oqvkSmJpmjYRuw4O1sYbByMiup1Yaa7nNGjUbasdaX", - "zk9aG5ZfrnpWfp+oWWqpI2m3MN8sWPM8lg23Pr6VbmJQjzAUz0BGKnEWlEdJSi9hxP4c1NnEY9TV", - "LeCR2qdpMxgcEVUvhSIi3djWUGZQPXNWv+WePaqwJLr9OKkL5JHtXLCCUmzZydkVEiXYj/xAjnPv", - "mkEgmnlA5RJMc9yBk/lmrIxsX1zTFCqpAGASScDqTXLHDppo2lVe5MuNh9cU3A3nvkk0g5BHTjrm", - "lLjdkV6EadmjlcrohkiU7Ceg7Djt/wDXoqQsC4Pv0orGOHijd1G+p8n68vyuc4PPNeKa6hO/8a9t", - "1w5ifjJPYGvGdcU5YdOtfiMlqf3JipXpGP4KlEfji3BbHPrz1r2v4kRGTw7o8ikn72TjpxXz1pL3", - "lr4tiuba3eeKEgzhRnAJr6E1h38TaFplnaI0V0gJaKb5OCPU9a+nw0k8LbqfztxBG2YTfmfL2syy", - "6ZrUF7Dw6PyM9R6V6N4c+KKaTiSw1bUdHeQASGMlQ3scda6K7+Gkrpm8USE8hRnafxqI+DLmDwnq", - "Wnx6db3Hmr+6jkiBAbGN27qMe1b0MyqYaDSjddjwa+DhWd3oz2fSfHfxAutCt7+Kc6xYSx/u5ZbO", - "OcFfTOMiue8ZeLr7xToEGk6vY6TZyWLGTzY7do5BkHgjP9K89+H6eOfh/fgBTf6RKf39nuOM/wB5", - "c9DXSeO73R/F9n9qksNU0PXIFzBdom4MR/C+OormlnlX2/LLDpxf2luvVHNLLml/Edux57JeQhTG", - "LhJJsYEKEbs9s4yR+OKpK011emG3ht1nCHCyv97jrkcgD61V0jRZLpZIb2b+zBu3ExxZLNntjr+N", - "akfg6/1Se6GnmG6gizjfIqO+OuFyDk+ldGLzKdvflZfcdFDB0YaxiFnpl1Yi3a+ujcNK+WeNjhT2", - "x/jXZ7NURZrWPU75YHQZTziQw9K57wJf6Tq+tS+Ftdv5tEuFfZam5gG1iD9wnPBr2DxB4P1DQtB/", - "tOA/2tDAPnjt0/ebMdQO/wBBV4XPMJTmqNepaXRvqn57HBmGDqv36SujCt/GXjmzgMMetTPGFwod", - "c1Npvj/xJp+hWelXNjp2pWdqAI1liweO5PrzXLeH9e03xNry6fpc2++KnbBL+7ZiOwz39q6680HV", - "LSJnutNuoY0BJcxnA/GvoquKotqMqiv2bWx4yp1YfY/A6rwx8X5tAW/STw9HGt1dtcSC36cgDB+g", - "FN1P4n6R4o+IkEviBdYs9GtbTNqlu5XE5Y7mbaecKAB+NeeAQyDcrRuOxUg002sT87Vx612Sc+VQ", - "VrIwjNKTm1qz0HTvHVjF8Q9Jjj8QXz6Q0xe4DyMWCqCQhBHQnAzXt2sfEPwdaeC7/VIJ7e5nhtmk", - "WBXwWYDgfnXyStgkN4ZYtqtjacgEEHqKt2Zeze82QWkhuITFKJIgw2n0HY+9c8KmIhFr4r7a7HVK", - "WHquLlpbstz6U0++8YJpcDzyeGtVkdAzfZ5mQLkZxnn1rsfDs8usaHJd3wt7GYTvEsUcvmA7SVJz", - "9Qa+PLi5nOk2Frbh7NrWMqs0ExV5PTee+KrWWq+JtNYR2us3caklsFs5JOTXRRxDuue6+4569KD+", - "Fr8j6+8R+ItN8OataWlw9xdTTwtM32aEuIUBxuc/wgngeuD6VWh8V6RK0aedNE8jBFEkLKSxOAOn", - "c18wWvjDxjY67dail+k881ukEizRhgyIzMOPqx/Otqb4r+Kp7a2E1lYMYruO43ouCShyB+eK0+sS", - "jJ2tbzvcz9hTaXc+s2sr1eDbyE+3NUFuI2mdA6F0JVwD0IOCD714UPj/AK22mCN9MMUgx864fNcv", - "ofxE8O2Ph+wXUdAuJdUYGTUJzcODLMxyz8dckk10yxiUlHR3/rqYwwl4uVz6ekmjhUNNLHGrNhSz", - "AZJ7D1PtRXhln8WvDmn6/LdWVlJcRtFGqRXcpcIcsWZd3Q8qM9sUVDxTb0S08xywaVrtnVXfwW8V", - "X120bXOmwIfuNuZifwArGf8AZh1W6uc6l4htkXdgpaxEkj1yf8K+3HRWmAKjHBqCcmNwE+UZ9K/N", - "3llO5+z1+Nc1qQac7L0R86+EvgP4d8M222O3N1c7t0lxOAWfv06Cu7ufh9okoUzWcTYXglATXdSX", - "U/2vHmcY9BUMjs/3jnj0rpVCMVZHzNSpOpJyk7s8ovfAeiwMHWB22j5VycA1hT+DFnuN1tH5Y6/M", - "gx/9evXjFG7Hcu7HqTTyqow2gDgVjKirk81jwi+8F3cYBkitZI/UEg/1rmLnwbHkn7KSpPpkV9JX", - "aI7YZQwyODXG6iAZymBsHQDpWMqTjsy1JPofO1z4Z0tLrZc2aCTPoePfIrMm8DaBJcNJbQCGZwQz", - "Cc7jn69K+i1sLN43d7eNnx1I5rOudNsCcm1iJC9xXJNyb1NUo9j5xufhfYXWHECs2clsBm+ua14t", - "P8S6ZCtvZaxcNHGNqRypuAHpzXpGoWduisUj8skfwMR/KuO1G5uLXT90E0qNnruz/OpqVY1bQqRU", - "vVXGsLG107HiniD4b3Op+KzrKN/Z+olgzSWi+WC397A6H6V67oXijxXpfh2LT9esH1x0XYLlcIzr", - "j+MdCfeuh0W4lu9L33DLK4ONxUZ/lXQ3VtAqAiJQSuTSxeFw2IjGnUgmlsZexlB+7I+S/HXhiO51", - "v+3fBlvqej3nm7rmxziLd13Ic4HPbpXqvgLxlZ6lYppXj3w/aWOpRrhdREAEc/8AvEfdb9K9QMEJ", - "fYYoyp6gr1qhcaZp8s4ElpCwaQAgr7GtKuGUsOqXPJW2alqjD2XvbL7jzX4g6BcravrXw/1PTbxE", - "XM+lM6sSB/FGc5/4DXDfDrxVoHiXUzo/ii7n0DWGfbBKAPJlP905+634817Ne6PplrqMdxb2kUU0", - "Th42XPBHOa8T13TbB9SiZrWEs05LHbyTya7sJPHQw3svrDfZtK69d7nHWw1BSvKmtT2XxF4BvtN8", - "Py32lynWXiG820aBZGXvt5wT7V4pp/i3SNU8Rw6YJJLG/ebywl4vlhX/ALrE8A/Wu20vxNr1nFFb", - "2+qXSQoNqISGAA4xzmvK/jBDDLr2l6m0MQv7mBjcTIgUyEEYJxgE+9Y5bnmZUqzw+Ikpt7O1noZS", - "y7Czs4po9rm8IeIYEJfS7h1xw0WHB/I1yZMUd5JbSMiTxth42OGU+hFd18Ata1XVPhHImo3094LW", - "58qAyHJRMD5c9SPrXEftI6ZY21lous29skGpzTGOa4jJVnUDIBx1+vWjL+Nq0sx+qV6a7XX+TJq5", - "BDk5oS+8aIkORhevFRPbRFsFV61pfs7Tya14U1uw1by9QtbaVfISeNWKbuuCRn9a7/4paVp2jfDx", - "tQ0u0hsrwXCL5kY7E8jHSvapcUUJ4z6o6bve1+hxVsoqU4cymeSvYw5UlAcNRUNhczT226V97cck", - "CivqJ00meTzNH//Z", - "--0016e6d99d0572dfaf047eb9ac2e--",//partend, then complete - "" - ].join("\r\n") -}); diff --git a/test/pummel/test-multipart.js b/test/pummel/test-multipart.js deleted file mode 100644 index dd79af02904..00000000000 --- a/test/pummel/test-multipart.js +++ /dev/null @@ -1,140 +0,0 @@ -require("../common"); - -var http = require("http"), - multipart = require("multipart"), - sys = require("sys"), - fixture = require("../fixtures/multipart"), - events = require("events"), - testPart = function (expect, part) { - if (!expect) { - throw new Error("Got more parts than expected: "+ - JSON.stringify(part.headers)); - } - for (var i in expect) { - assert.equal(expect[i], part[i]); - } - }; - -var emails = fixture.messages.slice(0), - chunkSize = 1; // set to minimum to forcibly expose boundary conditions. - // in a real scenario, this would be much much bigger. - -// test streaming messages through directly, as if they were in a file or something. -sys.puts("test "+emails.length+" emails"); -(function testEmails () { - - var email = emails.pop(), - curr = 0; - - if (!email) { - sys.puts("done testing emails"); - testGoodMessages(); - return; - } - sys.puts("testing email "+emails.length); - var expect = email.expect; - - var message = new (events.EventEmitter); - message.headers = email.headers; - - var mp = multipart.parse(message); - mp.addListener("partBegin", function (part) { - sys.puts(">> testing part #"+curr); - testPart(email.expect[curr ++], part); - }); - mp.addListener("complete", function () { - sys.puts("done with email "+emails.length); - process.nextTick(testEmails); - }); - // stream it through in chunks. - var emailBody = email.body; - process.nextTick(function s () { - if (emailBody) { - message.emit("data", emailBody.substr(0, chunkSize)); - emailBody = emailBody.substr(chunkSize); - process.nextTick(s); - } else { - message.emit("end"); - } - }); -})(); - -// run good HTTP messages test after previous test ends. -var server = http.createServer(function (req, res) { - sys.puts("HTTP mp request"); - var mp = multipart.parse(req), - curr = 0; - req.setBodyEncoding("binary"); - if (req.url !== "/bad") { - sys.puts("expected to be good"); - mp.addListener("partBegin", function (part) { - sys.puts(">> testing part #"+curr); - testPart(message.expect[curr ++], part); - }); - } else { - sys.puts("expected to be bad"); - } - mp.addListener("error", function (er) { - sys.puts("!! error occurred"); - res.writeHead(400, {}); - res.write("bad"); - res.close(); - }); - mp.addListener("complete", function () { - res.writeHead(200, {}); - res.write("ok"); - res.close(); - }); - }), - message, - client = http.createClient(PORT); -server.listen(PORT); - -// could dry these two up a bit. -function testGoodMessages () { - var httpMessages = fixture.messages.slice(0); - sys.puts("testing "+httpMessages.length+" good messages"); - (function testHTTP () { - message = httpMessages.pop(); - if (!message) { - testBadMessages(); - return; - } - sys.puts("test message "+httpMessages.length); - var req = client.request("POST", "/", message.headers); - req.write(message.body, "binary"); - req.addListener('response', function (res) { - var buff = ""; - res.addListener("data", function (chunk) { buff += chunk }); - res.addListener("end", function () { - assert.equal(buff, "ok"); - process.nextTick(testHTTP); - }); - }); - req.close(); - })(); -} - -function testBadMessages () { - var httpMessages = fixture.badMessages.slice(0); - sys.puts("testing "+httpMessages.length+" bad messages"); - (function testHTTP () { - message = httpMessages.pop(); - if (!message) { - server.close() - return; - } - sys.puts("test message "+httpMessages.length); - var req = client.request("POST", "/bad", message.headers); - req.write(message.body, "binary"); - req.addListener('response', function (res) { - var buff = ""; - res.addListener("data", function (chunk) { buff += chunk }); - res.addListener("end", function () { - assert.equal(buff, "bad"); - process.nextTick(testHTTP); - }); - }); - req.close(); - })(); -} From c0e18f37d40f0766fa214e6e3eaed6fa7caa72c0 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 2 Apr 2010 16:02:48 -0700 Subject: [PATCH 04/73] Don't reference fixtures/multipart.js --- test/simple/test-file-read-stream.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/simple/test-file-read-stream.js b/test/simple/test-file-read-stream.js index 3ac308b9a26..de8ff632597 100644 --- a/test/simple/test-file-read-stream.js +++ b/test/simple/test-file-read-stream.js @@ -3,7 +3,7 @@ require('../common'); var path = require('path'), fs = require('fs'), - fn = path.join(fixturesDir, 'multipart.js'), + fn = path.join(fixturesDir, 'test_ca.pem'), file = fs.createReadStream(fn), callbacks = { From ae805f10573e008702741a1e1bf85ce974968d52 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 2 Apr 2010 16:15:53 -0700 Subject: [PATCH 05/73] Emit 'error' on tcp connection DNS error --- lib/net.js | 56 +++++++++++++++++++++++++++++------------------- src/node_net2.cc | 10 +++++---- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/lib/net.js b/lib/net.js index 191d872c07e..41f2be08c6b 100644 --- a/lib/net.js +++ b/lib/net.js @@ -617,11 +617,15 @@ Stream.prototype.connect = function () { // TODO dns resolution on arguments[1] var port = arguments[0]; self._resolving = true; - lookupDomainName(arguments[1], function (ip, isV4) { - self.type = isV4 ? 'tcp4' : 'tcp6'; - self.fd = socket(self.type); - self._resolving = false; - doConnect(self, port, ip); + lookupDomainName(arguments[1], function (err, ip, isV4) { + if (err) { + self.emit('error', err); + } else { + self.type = isV4 ? 'tcp4' : 'tcp6'; + self.fd = socket(self.type); + self._resolving = false; + doConnect(self, port, ip); + } }); } else { self.fd = socket('unix'); @@ -761,7 +765,6 @@ exports.createServer = function (listener) { // callback(dn, isV4 function lookupDomainName (dn, callback) { var kind = isIP(dn); - debug('kind = ' + kind); if (kind) { // Always wait until the next tick this is so people can do // @@ -769,23 +772,28 @@ function lookupDomainName (dn, callback) { // server.addListener('listening', fn); // // Marginally slower, but a lot fewer WTFs. - process.nextTick(function () { callback(dn, kind == 4 ? true : false); }) + process.nextTick(function () { + callback(null, dn, kind == 4 ? true : false); + }); } else { debug("getaddrinfo 4 " + dn); - getaddrinfo(dn, 4, function (r4) { - if (r4 instanceof Error) throw r4; - if (r4.length > 0) { + getaddrinfo(dn, 4, function (err, r4) { + if (err) { + callback(err); + } else if (r4.length > 0) { debug("getaddrinfo 4 found " + r4); - callback(r4[0], true); + callback(null, r4[0], true); } else { debug("getaddrinfo 6 " + dn); - getaddrinfo(dn, 6, function (r6) { - if (r6 instanceof Error) throw r6; - if (r6.length < 0) { - throw new Error("No address associated with hostname " + dn); + getaddrinfo(dn, 6, function (err, r6) { + if (err) { + callback(err); + } else if (r6.length == 0) { + callback(new Error("No address associated with hostname " + dn)); + } else { + debug("getaddrinfo 6 found " + r6); + callback(null, r6[0], false); } - debug("getaddrinfo 6 found " + r6); - callback(r6[0], false); }); } }); @@ -847,11 +855,15 @@ Server.prototype.listen = function () { } else { // the first argument is the port, the second an IP var port = arguments[0]; - lookupDomainName(arguments[1], function (ip, isV4) { - self.type = isV4 ? 'tcp4' : 'tcp6'; - self.fd = socket(self.type); - bind(self.fd, port, ip); - self._doListen(); + lookupDomainName(arguments[1], function (err, ip, isV4) { + if (err) { + self.emit('error', err); + } else { + self.type = isV4 ? 'tcp4' : 'tcp6'; + self.fd = socket(self.type); + bind(self.fd, port, ip); + self._doListen(); + } }); } }; diff --git a/src/node_net2.cc b/src/node_net2.cc index de32dc419fd..2ba0f3f1ac1 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -1089,11 +1089,12 @@ static int AfterResolve(eio_req *req) { struct resolve_request * rreq = (struct resolve_request *)(req->data); HandleScope scope; - Local argv[1]; + Local argv[2]; if (req->result != 0) { + argv[1] = Array::New(); if (req->result == EAI_NODATA) { - argv[0] = Array::New(); + argv[0] = Local::New(Null()); } else { argv[0] = ErrnoException(req->result, "getaddrinfo", @@ -1127,12 +1128,13 @@ static int AfterResolve(eio_req *req) { address = address->ai_next; } - argv[0] = results; + argv[0] = Local::New(Null()); + argv[1] = results; } TryCatch try_catch; - rreq->cb->Call(Context::GetCurrent()->Global(), 1, argv); + rreq->cb->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { FatalException(try_catch); From cd577d503d05ded96f11fa97d538509d87debc12 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 4 Apr 2010 18:07:32 -0700 Subject: [PATCH 06/73] Upgrade V8 to 2.2.0.3 --- deps/v8/ChangeLog | 7 + deps/v8/include/v8.h | 7 +- deps/v8/src/SConscript | 1 + deps/v8/src/api.cc | 6 +- deps/v8/src/builtins.cc | 4 +- deps/v8/src/date.js | 33 +- deps/v8/src/frame-element.h | 2 +- deps/v8/src/heap.cc | 24 +- deps/v8/src/objects-inl.h | 13 +- deps/v8/src/objects.cc | 29 +- deps/v8/src/objects.h | 7 + deps/v8/src/regexp.js | 45 +- deps/v8/src/register-allocator.h | 2 +- deps/v8/src/runtime.cc | 630 ++---------------- deps/v8/src/runtime.h | 1 - deps/v8/src/string.js | 151 +++-- deps/v8/src/{type-info-inl.h => type-info.cc} | 6 +- deps/v8/src/type-info.h | 2 +- deps/v8/src/v8-counters.h | 1 + deps/v8/src/version.cc | 6 +- deps/v8/test/cctest/test-strings.cc | 5 +- deps/v8/tools/gyp/v8.gyp | 2 +- deps/v8/tools/visual_studio/v8_base.vcproj | 2 +- .../v8/tools/visual_studio/v8_base_arm.vcproj | 2 +- .../v8/tools/visual_studio/v8_base_x64.vcproj | 2 +- 25 files changed, 258 insertions(+), 732 deletions(-) rename deps/v8/src/{type-info-inl.h => type-info.cc} (95%) diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 0de330847b4..a15cce80d0d 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,10 @@ +2010-03-29: Version 2.2.0 + + Fixed a few minor bugs. + + Performance improvements for string operations. + + 2010-03-26: Version 2.1.10 Fixed scons build issues. diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index f64b3867367..90c43831f41 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -855,12 +855,15 @@ class V8EXPORT String : public Primitive { * \param start The starting position within the string at which * copying begins. * \param length The number of bytes to copy from the string. - * \return The number of characters copied to the buffer + * \param nchars The number of characters written. + * \return The number of bytes copied to the buffer * excluding the NULL terminator. */ int Write(uint16_t* buffer, int start = 0, int length = -1) const; // UTF-16 int WriteAscii(char* buffer, int start = 0, int length = -1) const; // ASCII - int WriteUtf8(char* buffer, int length = -1) const; // UTF-8 + int WriteUtf8(char* buffer, + int length = -1, + int* nchars = NULL) const; // UTF-8 /** * A zero length string. diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index a1d4796b7fd..1f1c1c18339 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -102,6 +102,7 @@ SOURCES = { stub-cache.cc token.cc top.cc + type-info.cc unicode.cc utils.cc v8-counters.cc diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 2100480e858..3ba22d63ea6 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -2639,7 +2639,7 @@ int String::Utf8Length() const { } -int String::WriteUtf8(char* buffer, int capacity) const { +int String::WriteUtf8(char* buffer, int capacity, int *ncharsRef) const { if (IsDeadCheck("v8::String::WriteUtf8()")) return 0; LOG_API("String::WriteUtf8"); ENTER_V8; @@ -2653,10 +2653,12 @@ int String::WriteUtf8(char* buffer, int capacity) const { int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1); int i; int pos = 0; + int nchars = 0; for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { i::uc32 c = write_input_buffer.GetNext(); int written = unibrow::Utf8::Encode(buffer + pos, c); pos += written; + nchars++; } if (i < len) { // For the last characters we need to check the length for each one @@ -2670,12 +2672,14 @@ int String::WriteUtf8(char* buffer, int capacity) const { for (int j = 0; j < written; j++) buffer[pos + j] = intermediate[j]; pos += written; + nchars++; } else { // We've reached the end of the buffer break; } } } + if (ncharsRef) *ncharsRef = nchars; if (i == len && (capacity == -1 || pos < capacity)) buffer[pos++] = '\0'; return pos; diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 122fbba2c4a..feb912f4147 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -495,7 +495,9 @@ BUILTIN(ArrayShift) { } if (Heap::new_space()->Contains(elms)) { - array->set_elements(LeftTrimFixedArray(elms)); + // As elms still in the same space they used to be (new space), + // there is no need to update remembered set. + array->set_elements(LeftTrimFixedArray(elms), SKIP_WRITE_BARRIER); } else { // Shift the elements. AssertNoAllocation no_gc; diff --git a/deps/v8/src/date.js b/deps/v8/src/date.js index c7c39406faf..46769c6bdfa 100644 --- a/deps/v8/src/date.js +++ b/deps/v8/src/date.js @@ -121,9 +121,16 @@ function EquivalentTime(t) { } -// Because computing the DST offset is a pretty expensive operation -// we keep a cache of last computed offset along with a time interval +// local_time_offset is initialized when the DST_offset_cache is missed. +// It must not be used until after a call to DaylightSavingsOffset(). +// In this way, only one check, for a DST cache miss, is needed. +var local_time_offset; + + +// Because computing the DST offset is an expensive operation, +// we keep a cache of the last computed DST offset along with a time interval // where we know the cache is valid. +// When the cache is valid, local_time_offset is also valid. var DST_offset_cache = { // Cached DST offset. offset: 0, @@ -149,6 +156,11 @@ function DaylightSavingsOffset(t) { // If the time fits in the cached interval, return the cached offset. if (t <= end) return cache.offset; + // If the cache misses, the local_time_offset may not be initialized. + if (IS_UNDEFINED(local_time_offset)) { + local_time_offset = %DateLocalTimeOffset(); + } + // Compute a possible new interval end. var new_end = end + cache.increment; @@ -185,6 +197,10 @@ function DaylightSavingsOffset(t) { } } + // If the cache misses, the local_time_offset may not be initialized. + if (IS_UNDEFINED(local_time_offset)) { + local_time_offset = %DateLocalTimeOffset(); + } // Compute the DST offset for the time and shrink the cache interval // to only contain the time. This allows fast repeated DST offset // computations for the same time. @@ -215,11 +231,11 @@ function WeekDay(time) { return Modulo(DAY(time) + 4, 7); } -var local_time_offset = %DateLocalTimeOffset(); function LocalTime(time) { if (NUMBER_IS_NAN(time)) return time; - return time + local_time_offset + DaylightSavingsOffset(time); + // DaylightSavingsOffset called before local_time_offset used. + return time + DaylightSavingsOffset(time) + local_time_offset; } function LocalTimeNoCheck(time) { @@ -228,6 +244,8 @@ function LocalTimeNoCheck(time) { } // Inline the DST offset cache checks for speed. + // The cache is hit, or DaylightSavingsOffset is called, + // before local_time_offset is used. var cache = DST_offset_cache; if (cache.start <= time && time <= cache.end) { var dst_offset = cache.offset; @@ -240,6 +258,11 @@ function LocalTimeNoCheck(time) { function UTC(time) { if (NUMBER_IS_NAN(time)) return time; + // local_time_offset is needed before the call to DaylightSavingsOffset, + // so it may be uninitialized. + if (IS_UNDEFINED(local_time_offset)) { + local_time_offset = %DateLocalTimeOffset(); + } var tmp = time - local_time_offset; return tmp - DaylightSavingsOffset(tmp); } @@ -566,7 +589,7 @@ function TimeString(time) { function LocalTimezoneString(time) { var timezoneOffset = - (local_time_offset + DaylightSavingsOffset(time)) / msPerMinute; + (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute; var sign = (timezoneOffset >= 0) ? 1 : -1; var hours = FLOOR((sign * timezoneOffset)/60); var min = FLOOR((sign * timezoneOffset)%60); diff --git a/deps/v8/src/frame-element.h b/deps/v8/src/frame-element.h index 83db5c3342d..48bb354aa85 100644 --- a/deps/v8/src/frame-element.h +++ b/deps/v8/src/frame-element.h @@ -28,7 +28,7 @@ #ifndef V8_FRAME_ELEMENT_H_ #define V8_FRAME_ELEMENT_H_ -#include "type-info-inl.h" +#include "type-info.h" #include "macro-assembler.h" #include "zone.h" diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 1f1599a79bf..5421dcc1956 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1961,8 +1961,9 @@ Object* Heap::AllocateConsString(String* first, String* second) { return MakeOrFindTwoCharacterString(c1, c2); } - bool is_ascii = first->IsAsciiRepresentation() - && second->IsAsciiRepresentation(); + bool first_is_ascii = first->IsAsciiRepresentation(); + bool second_is_ascii = second->IsAsciiRepresentation(); + bool is_ascii = first_is_ascii && second_is_ascii; // Make sure that an out of memory exception is thrown if the length // of the new cons string is too large. @@ -1997,6 +1998,25 @@ Object* Heap::AllocateConsString(String* first, String* second) { for (int i = 0; i < second_length; i++) *dest++ = src[i]; return result; } else { + // For short external two-byte strings we check whether they can + // be represented using ascii. + if (!first_is_ascii) { + first_is_ascii = first->IsExternalTwoByteStringWithAsciiChars(); + } + if (first_is_ascii && !second_is_ascii) { + second_is_ascii = second->IsExternalTwoByteStringWithAsciiChars(); + } + if (first_is_ascii && second_is_ascii) { + Object* result = AllocateRawAsciiString(length); + if (result->IsFailure()) return result; + // Copy the characters into the new object. + char* dest = SeqAsciiString::cast(result)->GetChars(); + String::WriteToFlat(first, dest, 0, first_length); + String::WriteToFlat(second, dest + first_length, 0, second_length); + Counters::string_add_runtime_ext_to_ascii.Increment(); + return result; + } + Object* result = AllocateRawTwoByteString(length); if (result->IsFailure()) return result; // Copy the characters into the new object. diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index a26da7dd629..d363d4d6ab2 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -255,6 +255,16 @@ bool String::IsTwoByteRepresentation() { } +bool String::IsExternalTwoByteStringWithAsciiChars() { + if (!IsExternalTwoByteString()) return false; + const uc16* data = ExternalTwoByteString::cast(this)->resource()->data(); + for (int i = 0, len = length(); i < len; i++) { + if (data[i] > kMaxAsciiCharCode) return false; + } + return true; +} + + bool StringShape::IsCons() { return (type_ & kStringRepresentationMask) == kConsStringTag; } @@ -732,7 +742,8 @@ Object* Object::GetProperty(String* key, PropertyAttributes* attributes) { } else { \ ASSERT(mode == SKIP_WRITE_BARRIER); \ ASSERT(Heap::InNewSpace(object) || \ - !Heap::InNewSpace(READ_FIELD(object, offset))); \ + !Heap::InNewSpace(READ_FIELD(object, offset)) || \ + Page::IsRSetSet(object->address(), offset)); \ } #define READ_DOUBLE_FIELD(p, offset) \ diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index a1fbc992770..02ea5b0455d 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -4660,13 +4660,38 @@ bool String::IsEqualTo(Vector str) { } +template +static inline uint32_t HashSequentialString(const schar* chars, int length) { + StringHasher hasher(length); + if (!hasher.has_trivial_hash()) { + int i; + for (i = 0; hasher.is_array_index() && (i < length); i++) { + hasher.AddCharacter(chars[i]); + } + for (; i < length; i++) { + hasher.AddCharacterNoIndex(chars[i]); + } + } + return hasher.GetHashField(); +} + + uint32_t String::ComputeAndSetHash() { // Should only be called if hash code has not yet been computed. ASSERT(!(hash_field() & kHashComputedMask)); + const int len = length(); + // Compute the hash code. - StringInputBuffer buffer(this); - uint32_t field = ComputeHashField(&buffer, length()); + uint32_t field = 0; + if (StringShape(this).IsSequentialAscii()) { + field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len); + } else if (StringShape(this).IsSequentialTwoByte()) { + field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len); + } else { + StringInputBuffer buffer(this); + field = ComputeHashField(&buffer, len); + } // Store the hash code in the object. set_hash_field(field); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 01977f0929d..5a0db0177ba 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3919,6 +3919,13 @@ class String: public HeapObject { inline bool IsAsciiRepresentation(); inline bool IsTwoByteRepresentation(); + // Check whether this string is an external two-byte string that in + // fact contains only ascii characters. + // + // Such strings may appear when the embedder prefers two-byte + // representations even for ascii data. + inline bool IsExternalTwoByteStringWithAsciiChars(); + // Get and set individual two byte chars in the string. inline void Set(int index, uint16_t value); // Get individual two byte char in the string. Repeated calls diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index dc1b0429f70..e2492f7245b 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -344,7 +344,6 @@ function RegExpToString() { // on the captures array of the last successful match and the subject string // of the last successful match. function RegExpGetLastMatch() { - if (lastMatchInfoOverride) { return lastMatchInfoOverride[0]; } var regExpSubject = LAST_SUBJECT(lastMatchInfo); return SubString(regExpSubject, lastMatchInfo[CAPTURE0], @@ -353,11 +352,6 @@ function RegExpGetLastMatch() { function RegExpGetLastParen() { - if (lastMatchInfoOverride) { - var override = lastMatchInfoOverride; - if (override.length <= 3) return ''; - return override[override.length - 3]; - } var length = NUMBER_OF_CAPTURES(lastMatchInfo); if (length <= 2) return ''; // There were no captures. // We match the SpiderMonkey behavior: return the substring defined by the @@ -374,32 +368,17 @@ function RegExpGetLastParen() { function RegExpGetLeftContext() { - var start_index; - var subject; - if (!lastMatchInfoOverride) { - start_index = lastMatchInfo[CAPTURE0]; - subject = LAST_SUBJECT(lastMatchInfo); - } else { - var override = lastMatchInfoOverride; - start_index = override[override.length - 2]; - subject = override[override.length - 1]; - } - return SubString(subject, 0, start_index); + return SubString(LAST_SUBJECT(lastMatchInfo), + 0, + lastMatchInfo[CAPTURE0]); } function RegExpGetRightContext() { - var start_index; - var subject; - if (!lastMatchInfoOverride) { - start_index = lastMatchInfo[CAPTURE1]; - subject = LAST_SUBJECT(lastMatchInfo); - } else { - var override = lastMatchInfoOverride; - subject = override[override.length - 1]; - start_index = override[override.length - 2] + subject.length; - } - return SubString(subject, start_index, subject.length); + var subject = LAST_SUBJECT(lastMatchInfo); + return SubString(subject, + lastMatchInfo[CAPTURE1], + subject.length); } @@ -408,10 +387,6 @@ function RegExpGetRightContext() { // called with indices from 1 to 9. function RegExpMakeCaptureGetter(n) { return function() { - if (lastMatchInfoOverride) { - if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n]; - return ''; - } var index = n * 2; if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return ''; var matchStart = lastMatchInfo[CAPTURE(index)]; @@ -436,12 +411,6 @@ var lastMatchInfo = [ 0, // REGEXP_FIRST_CAPTURE + 1 ]; -// Override last match info with an array of actual substrings. -// Used internally by replace regexp with function. -// The array has the format of an "apply" argument for a replacement -// function. -var lastMatchInfoOverride = null; - // ------------------------------------------------------------------- function SetupRegExp() { diff --git a/deps/v8/src/register-allocator.h b/deps/v8/src/register-allocator.h index 0fbc83b821f..45645339114 100644 --- a/deps/v8/src/register-allocator.h +++ b/deps/v8/src/register-allocator.h @@ -29,7 +29,7 @@ #define V8_REGISTER_ALLOCATOR_H_ #include "macro-assembler.h" -#include "type-info-inl.h" +#include "type-info.h" #if V8_TARGET_ARCH_IA32 #include "ia32/register-allocator-ia32.h" diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index c77d518371c..b3498152193 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1567,91 +1567,9 @@ static Object* Runtime_CharFromCode(Arguments args) { return CharFromCode(args[0]); } - -class FixedArrayBuilder { - public: - explicit FixedArrayBuilder(int initial_capacity) - : array_(Factory::NewFixedArrayWithHoles(initial_capacity)), - length_(0) { - // Require a non-zero initial size. Ensures that doubling the size to - // extend the array will work. - ASSERT(initial_capacity > 0); - } - - explicit FixedArrayBuilder(Handle backing_store) - : array_(backing_store), - length_(0) { - // Require a non-zero initial size. Ensures that doubling the size to - // extend the array will work. - ASSERT(backing_store->length() > 0); - } - - bool HasCapacity(int elements) { - int length = array_->length(); - int required_length = length_ + elements; - return (length >= required_length); - } - - void EnsureCapacity(int elements) { - int length = array_->length(); - int required_length = length_ + elements; - if (length < required_length) { - int new_length = length; - do { - new_length *= 2; - } while (new_length < required_length); - Handle extended_array = - Factory::NewFixedArrayWithHoles(new_length); - array_->CopyTo(0, *extended_array, 0, length_); - array_ = extended_array; - } - } - - void Add(Object* value) { - ASSERT(length_ < capacity()); - array_->set(length_, value); - length_++; - } - - void Add(Smi* value) { - ASSERT(length_ < capacity()); - array_->set(length_, value); - length_++; - } - - Handle array() { - return array_; - } - - int length() { - return length_; - } - - int capacity() { - return array_->length(); - } - - Handle ToJSArray() { - Handle result_array = Factory::NewJSArrayWithElements(array_); - result_array->set_length(Smi::FromInt(length_)); - return result_array; - } - - Handle ToJSArray(Handle target_array) { - target_array->set_elements(*array_); - target_array->set_length(Smi::FromInt(length_)); - return target_array; - } - - private: - Handle array_; - int length_; -}; - - // Forward declarations. -const int kStringBuilderConcatHelperLengthBits = 11; -const int kStringBuilderConcatHelperPositionBits = 19; +static const int kStringBuilderConcatHelperLengthBits = 11; +static const int kStringBuilderConcatHelperPositionBits = 19; template static inline void StringBuilderConcatHelper(String*, @@ -1659,19 +1577,15 @@ static inline void StringBuilderConcatHelper(String*, FixedArray*, int); -typedef BitField - StringBuilderSubstringLength; -typedef BitField - StringBuilderSubstringPosition; - +typedef BitField StringBuilderSubstringLength; +typedef BitField StringBuilderSubstringPosition; class ReplacementStringBuilder { public: ReplacementStringBuilder(Handle subject, int estimated_part_count) - : array_builder_(estimated_part_count), - subject_(subject), + : subject_(subject), + parts_(Factory::NewFixedArray(estimated_part_count)), + part_count_(0), character_count_(0), is_ascii_(subject->IsAsciiRepresentation()) { // Require a non-zero initial size. Ensures that doubling the size to @@ -1679,35 +1593,38 @@ class ReplacementStringBuilder { ASSERT(estimated_part_count > 0); } - static inline void AddSubjectSlice(FixedArrayBuilder* builder, - int from, - int to) { + void EnsureCapacity(int elements) { + int length = parts_->length(); + int required_length = part_count_ + elements; + if (length < required_length) { + int new_length = length; + do { + new_length *= 2; + } while (new_length < required_length); + Handle extended_array = + Factory::NewFixedArray(new_length); + parts_->CopyTo(0, *extended_array, 0, part_count_); + parts_ = extended_array; + } + } + + void AddSubjectSlice(int from, int to) { ASSERT(from >= 0); int length = to - from; ASSERT(length > 0); + // Can we encode the slice in 11 bits for length and 19 bits for + // start position - as used by StringBuilderConcatHelper? if (StringBuilderSubstringLength::is_valid(length) && StringBuilderSubstringPosition::is_valid(from)) { int encoded_slice = StringBuilderSubstringLength::encode(length) | StringBuilderSubstringPosition::encode(from); - builder->Add(Smi::FromInt(encoded_slice)); + AddElement(Smi::FromInt(encoded_slice)); } else { // Otherwise encode as two smis. - builder->Add(Smi::FromInt(-length)); - builder->Add(Smi::FromInt(from)); + AddElement(Smi::FromInt(-length)); + AddElement(Smi::FromInt(from)); } - } - - - void EnsureCapacity(int elements) { - array_builder_.EnsureCapacity(elements); - } - - - void AddSubjectSlice(int from, int to) { - AddSubjectSlice(&array_builder_, from, to); - // Can we encode the slice in 11 bits for length and 19 bits for - // start position - as used by StringBuilderConcatHelper? - IncrementCharacterCount(to - from); + IncrementCharacterCount(length); } @@ -1723,7 +1640,7 @@ class ReplacementStringBuilder { Handle ToString() { - if (array_builder_.length() == 0) { + if (part_count_ == 0) { return Factory::empty_string(); } @@ -1735,8 +1652,8 @@ class ReplacementStringBuilder { char* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, char_buffer, - *array_builder_.array(), - array_builder_.length()); + *parts_, + part_count_); } else { // Non-ASCII. joined_string = NewRawTwoByteString(character_count_); @@ -1745,8 +1662,8 @@ class ReplacementStringBuilder { uc16* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, char_buffer, - *array_builder_.array(), - array_builder_.length()); + *parts_, + part_count_); } return joined_string; } @@ -1759,14 +1676,8 @@ class ReplacementStringBuilder { character_count_ += by; } - Handle GetParts() { - Handle result = - Factory::NewJSArrayWithElements(array_builder_.array()); - result->set_length(Smi::FromInt(array_builder_.length())); - return result; - } - private: + Handle NewRawAsciiString(int size) { CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); } @@ -1779,12 +1690,14 @@ class ReplacementStringBuilder { void AddElement(Object* element) { ASSERT(element->IsSmi() || element->IsString()); - ASSERT(array_builder_.capacity() > array_builder_.length()); - array_builder_.Add(element); + ASSERT(parts_->length() > part_count_); + parts_->set(part_count_, element); + part_count_++; } - FixedArrayBuilder array_builder_; Handle subject_; + Handle parts_; + int part_count_; int character_count_; bool is_ascii_; }; @@ -2192,6 +2105,7 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { } + // Cap on the maximal shift in the Boyer-Moore implementation. By setting a // limit, we can fix the size of tables. static const int kBMMaxShift = 0xff; @@ -2955,468 +2869,6 @@ static Object* Runtime_StringMatch(Arguments args) { } -// Two smis before and after the match, for very long strings. -const int kMaxBuilderEntriesPerRegExpMatch = 5; - - -static void SetLastMatchInfoNoCaptures(Handle subject, - Handle last_match_info, - int match_start, - int match_end) { - // Fill last_match_info with a single capture. - last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); - AssertNoAllocation no_gc; - FixedArray* elements = FixedArray::cast(last_match_info->elements()); - RegExpImpl::SetLastCaptureCount(elements, 2); - RegExpImpl::SetLastInput(elements, *subject); - RegExpImpl::SetLastSubject(elements, *subject); - RegExpImpl::SetCapture(elements, 0, match_start); - RegExpImpl::SetCapture(elements, 1, match_end); -} - - -template -static bool SearchCharMultiple(Vector subject, - String* pattern, - schar pattern_char, - FixedArrayBuilder* builder, - int* match_pos) { - // Position of last match. - int pos = *match_pos; - int subject_length = subject.length(); - while (pos < subject_length) { - int match_end = pos + 1; - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); - if (new_pos >= 0) { - // Match has been found. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } - } - if (pos + 1 < subject_length) { - ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); - } - *match_pos = pos; - return true; -} - - -static bool SearchCharMultiple(Handle subject, - Handle pattern, - Handle last_match_info, - FixedArrayBuilder* builder) { - ASSERT(subject->IsFlat()); - ASSERT_EQ(1, pattern->length()); - uc16 pattern_char = pattern->Get(0); - // Treating position before first as initial "previous match position". - int match_pos = -1; - - for (;;) { // Break when search complete. - builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); - AssertNoAllocation no_gc; - if (subject->IsAsciiRepresentation()) { - if (pattern_char > String::kMaxAsciiCharCode) { - break; - } - Vector subject_vector = subject->ToAsciiVector(); - char pattern_ascii_char = static_cast(pattern_char); - bool complete = SearchCharMultiple(subject_vector, - *pattern, - pattern_ascii_char, - builder, - &match_pos); - if (complete) break; - } else { - Vector subject_vector = subject->ToUC16Vector(); - bool complete = SearchCharMultiple(subject_vector, - *pattern, - pattern_char, - builder, - &match_pos); - if (complete) break; - } - } - - if (match_pos >= 0) { - SetLastMatchInfoNoCaptures(subject, - last_match_info, - match_pos, - match_pos + 1); - return true; - } - return false; // No matches at all. -} - - -template -static bool SearchStringMultiple(Vector subject, - String* pattern, - Vector pattern_string, - FixedArrayBuilder* builder, - int* match_pos) { - int pos = *match_pos; - int subject_length = subject.length(); - int pattern_length = pattern_string.length(); - int max_search_start = subject_length - pattern_length; - bool is_ascii = (sizeof(schar) == 1); - StringSearchStrategy strategy = - InitializeStringSearch(pattern_string, is_ascii); - switch (strategy) { - case SEARCH_FAIL: return false; - case SEARCH_SHORT: - while (pos <= max_search_start) { - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - // Position of end of previous match. - int match_end = pos + pattern_length; - int new_pos = SimpleIndexOf(subject, pattern_string, match_end); - if (new_pos >= 0) { - // A match. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } - } - break; - case SEARCH_LONG: - while (pos <= max_search_start) { - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - int new_pos = ComplexIndexOf(subject, - pattern_string, - pos + pattern_length); - if (new_pos >= 0) { - // A match has been found. - if (new_pos > pos) { - ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } - } - break; - } - if (pos < max_search_start) { - ReplacementStringBuilder::AddSubjectSlice(builder, - pos + pattern_length, - subject_length); - } - *match_pos = pos; - return true; -} - - -static bool SearchStringMultiple(Handle subject, - Handle pattern, - Handle last_match_info, - FixedArrayBuilder* builder) { - ASSERT(subject->IsFlat()); - ASSERT(pattern->IsFlat()); - ASSERT(pattern->length() > 1); - - // Treating as if a previous match was before first character. - int match_pos = -pattern->length(); - - for (;;) { // Break when search complete. - builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); - AssertNoAllocation no_gc; - if (subject->IsAsciiRepresentation()) { - Vector subject_vector = subject->ToAsciiVector(); - if (pattern->IsAsciiRepresentation()) { - if (SearchStringMultiple(subject_vector, - *pattern, - pattern->ToAsciiVector(), - builder, - &match_pos)) break; - } else { - if (SearchStringMultiple(subject_vector, - *pattern, - pattern->ToUC16Vector(), - builder, - &match_pos)) break; - } - } else { - Vector subject_vector = subject->ToUC16Vector(); - if (pattern->IsAsciiRepresentation()) { - if (SearchStringMultiple(subject_vector, - *pattern, - pattern->ToAsciiVector(), - builder, - &match_pos)) break; - } else { - if (SearchStringMultiple(subject_vector, - *pattern, - pattern->ToUC16Vector(), - builder, - &match_pos)) break; - } - } - } - - if (match_pos >= 0) { - SetLastMatchInfoNoCaptures(subject, - last_match_info, - match_pos, - match_pos + pattern->length()); - return true; - } - return false; // No matches at all. -} - - -static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( - Handle subject, - Handle regexp, - Handle last_match_array, - FixedArrayBuilder* builder) { - ASSERT(subject->IsFlat()); - int match_start = -1; - int match_end = 0; - int pos = 0; - int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); - if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; - - OffsetsVector registers(required_registers); - Vector register_vector(registers.vector(), registers.length()); - int subject_length = subject->length(); - - for (;;) { // Break on failure, return on exception. - RegExpImpl::IrregexpResult result = - RegExpImpl::IrregexpExecOnce(regexp, - subject, - pos, - register_vector); - if (result == RegExpImpl::RE_SUCCESS) { - match_start = register_vector[0]; - builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); - if (match_end < match_start) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - match_start); - } - match_end = register_vector[1]; - HandleScope loop_scope; - builder->Add(*Factory::NewSubString(subject, match_start, match_end)); - if (match_start != match_end) { - pos = match_end; - } else { - pos = match_end + 1; - if (pos > subject_length) break; - } - } else if (result == RegExpImpl::RE_FAILURE) { - break; - } else { - ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); - return result; - } - } - - if (match_start >= 0) { - if (match_end < subject_length) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - subject_length); - } - SetLastMatchInfoNoCaptures(subject, - last_match_array, - match_start, - match_end); - return RegExpImpl::RE_SUCCESS; - } else { - return RegExpImpl::RE_FAILURE; // No matches at all. - } -} - - -static RegExpImpl::IrregexpResult SearchRegExpMultiple( - Handle subject, - Handle regexp, - Handle last_match_array, - FixedArrayBuilder* builder) { - - ASSERT(subject->IsFlat()); - int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); - if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; - - OffsetsVector registers(required_registers); - Vector register_vector(registers.vector(), registers.length()); - - RegExpImpl::IrregexpResult result = - RegExpImpl::IrregexpExecOnce(regexp, - subject, - 0, - register_vector); - - int capture_count = regexp->CaptureCount(); - int subject_length = subject->length(); - - // Position to search from. - int pos = 0; - // End of previous match. Differs from pos if match was empty. - int match_end = 0; - if (result == RegExpImpl::RE_SUCCESS) { - // Need to keep a copy of the previous match for creating last_match_info - // at the end, so we have two vectors that we swap between. - OffsetsVector registers2(required_registers); - Vector prev_register_vector(registers2.vector(), registers2.length()); - - do { - int match_start = register_vector[0]; - builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); - if (match_end < match_start) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - match_start); - } - match_end = register_vector[1]; - - { - // Avoid accumulating new handles inside loop. - HandleScope temp_scope; - // Arguments array to replace function is match, captures, index and - // subject, i.e., 3 + capture count in total. - Handle elements = Factory::NewFixedArray(3 + capture_count); - elements->set(0, *Factory::NewSubString(subject, - match_start, - match_end)); - for (int i = 1; i <= capture_count; i++) { - Handle substring = - Factory::NewSubString(subject, - register_vector[i * 2], - register_vector[i * 2 + 1]); - elements->set(i, *substring); - } - elements->set(capture_count + 1, Smi::FromInt(match_start)); - elements->set(capture_count + 2, *subject); - builder->Add(*Factory::NewJSArrayWithElements(elements)); - } - // Swap register vectors, so the last successful match is in - // prev_register_vector. - Vector tmp = prev_register_vector; - prev_register_vector = register_vector; - register_vector = tmp; - - if (match_end > match_start) { - pos = match_end; - } else { - pos = match_end + 1; - if (pos > subject_length) { - break; - } - } - - result = RegExpImpl::IrregexpExecOnce(regexp, - subject, - pos, - register_vector); - } while (result == RegExpImpl::RE_SUCCESS); - - if (result != RegExpImpl::RE_EXCEPTION) { - // Finished matching, with at least one match. - if (match_end < subject_length) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - subject_length); - } - - int last_match_capture_count = (capture_count + 1) * 2; - int last_match_array_size = - last_match_capture_count + RegExpImpl::kLastMatchOverhead; - last_match_array->EnsureSize(last_match_array_size); - AssertNoAllocation no_gc; - FixedArray* elements = FixedArray::cast(last_match_array->elements()); - RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); - RegExpImpl::SetLastSubject(elements, *subject); - RegExpImpl::SetLastInput(elements, *subject); - for (int i = 0; i < last_match_capture_count; i++) { - RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); - } - return RegExpImpl::RE_SUCCESS; - } - } - // No matches at all, return failure or exception result directly. - return result; -} - - -static Object* Runtime_RegExpExecMultiple(Arguments args) { - ASSERT(args.length() == 4); - HandleScope handles; - - CONVERT_ARG_CHECKED(String, subject, 1); - if (!subject->IsFlat()) { FlattenString(subject); } - CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); - CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); - CONVERT_ARG_CHECKED(JSArray, result_array, 3); - - ASSERT(last_match_info->HasFastElements()); - ASSERT(regexp->GetFlags().is_global()); - Handle result_elements; - if (result_array->HasFastElements()) { - result_elements = - Handle(FixedArray::cast(result_array->elements())); - } else { - result_elements = Factory::NewFixedArrayWithHoles(16); - } - FixedArrayBuilder builder(result_elements); - - if (regexp->TypeTag() == JSRegExp::ATOM) { - Handle pattern( - String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); - int pattern_length = pattern->length(); - if (pattern_length == 1) { - if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { - return *builder.ToJSArray(result_array); - } - return Heap::null_value(); - } - - if (!pattern->IsFlat()) FlattenString(pattern); - if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { - return *builder.ToJSArray(result_array); - } - return Heap::null_value(); - } - - ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); - - RegExpImpl::IrregexpResult result; - if (regexp->CaptureCount() == 0) { - result = SearchRegExpNoCaptureMultiple(subject, - regexp, - last_match_info, - &builder); - } else { - result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder); - } - if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); - if (result == RegExpImpl::RE_FAILURE) return Heap::null_value(); - ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); - return Failure::Exception(); -} - - static Object* Runtime_NumberToRadixString(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 2); diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 42af3df88a2..4175902c450 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -153,7 +153,6 @@ namespace internal { /* Regular expressions */ \ F(RegExpCompile, 3, 1) \ F(RegExpExec, 4, 1) \ - F(RegExpExecMultiple, 4, 1) \ \ /* Strings */ \ F(StringCharCodeAt, 2, 1) \ diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index f4489efa121..ca438fdde54 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -405,91 +405,97 @@ function addCaptureString(builder, matchInfo, index) { builder.addSpecialSlice(start, end); }; -// TODO(lrn): This array will survive indefinitely if replace is never -// called again. However, it will be empty, since the contents are cleared -// in the finally block. -var reusableReplaceArray = $Array(16); // Helper function for replacing regular expressions with the result of a -// function application in String.prototype.replace. +// function application in String.prototype.replace. The function application +// must be interleaved with the regexp matching (contrary to ECMA-262 +// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses +// the static properties of the RegExp constructor. Example: +// 'abcd'.replace(/(.)/g, function() { return RegExp.$1; } +// should be 'abcd' and not 'dddd' (or anything else). function StringReplaceRegExpWithFunction(subject, regexp, replace) { + var matchInfo = DoRegExpExec(regexp, subject, 0); + if (IS_NULL(matchInfo)) return subject; + + var result = new ReplaceResultBuilder(subject); + // There's at least one match. If the regexp is global, we have to loop + // over all matches. The loop is not in C++ code here like the one in + // RegExp.prototype.exec, because of the interleaved function application. + // Unfortunately, that means this code is nearly duplicated, here and in + // jsregexp.cc. if (regexp.global) { - var resultArray = reusableReplaceArray; - if (resultArray) { - reusableReplaceArray = null; - } else { - // Inside a nested replace (replace called from the replacement function - // of another replace) or we have failed to set the reusable array - // back due to an exception in a replacement function. Create a new - // array to use in the future, or until the original is written back. - resultArray = $Array(16); - } - try { - // Must handle exceptions thrown by the replace functions correctly, - // including unregistering global regexps. - var res = %RegExpExecMultiple(regexp, - subject, - lastMatchInfo, - resultArray); - regexp.lastIndex = 0; - if (IS_NULL(res)) { - // No matches at all. - return subject; - } - var len = res.length; - var i = 0; - if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) { - var match_start = 0; - while (i < len) { - var elem = res[i]; - if (%_IsSmi(elem)) { - if (elem > 0) { - match_start = (elem >> 11) + (elem & 0x7ff); - } else { - match_start = res[++i] - elem; - } - } else { - var func_result = replace.call(null, elem, match_start, subject); - if (!IS_STRING(func_result)) func_result = TO_STRING(func_result); - res[i] = func_result; - match_start += elem.length; + var previous = 0; + var startOfMatch; + if (NUMBER_OF_CAPTURES(matchInfo) == 2) { + // Both branches contain essentially the same loop except for the call + // to the replace function. The branch is put outside of the loop for + // speed + do { + startOfMatch = matchInfo[CAPTURE0]; + result.addSpecialSlice(previous, startOfMatch); + previous = matchInfo[CAPTURE1]; + var match = SubString(subject, startOfMatch, previous); + // Don't call directly to avoid exposing the built-in global object. + result.add(replace.call(null, match, startOfMatch, subject)); + // Can't use matchInfo any more from here, since the function could + // overwrite it. + // Continue with the next match. + // Increment previous if we matched an empty string, as per ECMA-262 + // 15.5.4.10. + if (previous == startOfMatch) { + // Add the skipped character to the output, if any. + if (previous < subject.length) { + result.addSpecialSlice(previous, previous + 1); } - i++; - } - } else { - while (i < len) { - var elem = res[i]; - if (!%_IsSmi(elem)) { - // elem must be an Array. - // Use the apply argument as backing for global RegExp properties. - lastMatchInfoOverride = elem; - var func_result = replace.apply(null, elem); - if (!IS_STRING(func_result)) func_result = TO_STRING(func_result); - res[i] = func_result; + previous++; + // Per ECMA-262 15.10.6.2, if the previous index is greater than the + // string length, there is no match + if (previous > subject.length) { + return result.generate(); } - i++; } - } - var result = new ReplaceResultBuilder(subject, res); - return result.generate(); - } finally { - lastMatchInfoOverride = null; - resultArray.length = 0; - reusableReplaceArray = resultArray; + matchInfo = DoRegExpExec(regexp, subject, previous); + } while (!IS_NULL(matchInfo)); + } else { + do { + startOfMatch = matchInfo[CAPTURE0]; + result.addSpecialSlice(previous, startOfMatch); + previous = matchInfo[CAPTURE1]; + result.add(ApplyReplacementFunction(replace, matchInfo, subject)); + // Can't use matchInfo any more from here, since the function could + // overwrite it. + // Continue with the next match. + // Increment previous if we matched an empty string, as per ECMA-262 + // 15.5.4.10. + if (previous == startOfMatch) { + // Add the skipped character to the output, if any. + if (previous < subject.length) { + result.addSpecialSlice(previous, previous + 1); + } + previous++; + // Per ECMA-262 15.10.6.2, if the previous index is greater than the + // string length, there is no match + if (previous > subject.length) { + return result.generate(); + } + } + matchInfo = DoRegExpExec(regexp, subject, previous); + } while (!IS_NULL(matchInfo)); } + + // Tack on the final right substring after the last match. + result.addSpecialSlice(previous, subject.length); + } else { // Not a global regexp, no need to loop. - var matchInfo = DoRegExpExec(regexp, subject, 0); - if (IS_NULL(matchInfo)) return subject; - - var result = new ReplaceResultBuilder(subject); result.addSpecialSlice(0, matchInfo[CAPTURE0]); var endOfMatch = matchInfo[CAPTURE1]; result.add(ApplyReplacementFunction(replace, matchInfo, subject)); // Can't use matchInfo any more from here, since the function could // overwrite it. result.addSpecialSlice(endOfMatch, subject.length); - return result.generate(); } + + return result.generate(); } @@ -888,11 +894,8 @@ function StringSup() { // ReplaceResultBuilder support. function ReplaceResultBuilder(str) { - if (%_ArgumentsLength() > 1) { - this.elements = %_Arguments(1); - } else { - this.elements = new $Array(); - } + this.__proto__ = void 0; + this.elements = new $Array(); this.special_string = str; } diff --git a/deps/v8/src/type-info-inl.h b/deps/v8/src/type-info.cc similarity index 95% rename from deps/v8/src/type-info-inl.h rename to deps/v8/src/type-info.cc index 90d3f55f9b8..b1bde599f4c 100644 --- a/deps/v8/src/type-info-inl.h +++ b/deps/v8/src/type-info.cc @@ -25,9 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_TYPE_INFO_INL_H_ -#define V8_TYPE_INFO_INL_H_ - +#include "v8.h" #include "type-info.h" #include "objects-inl.h" @@ -51,5 +49,3 @@ TypeInfo TypeInfo::TypeFromValue(Handle value) { } } // namespace v8::internal - -#endif // V8_TYPE_INFO_INL_H_ diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index 15bc1280235..1d82634092c 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -130,7 +130,7 @@ class TypeInfo { return false; } - static inline TypeInfo TypeFromValue(Handle value); + static TypeInfo TypeFromValue(Handle value); inline bool IsUnknown() { return type_ == kUnknownType; diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index a5f3594ca71..bd671a13fe5 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -166,6 +166,7 @@ namespace internal { SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \ SC(string_add_runtime, V8.StringAddRuntime) \ SC(string_add_native, V8.StringAddNative) \ + SC(string_add_runtime_ext_to_ascii, V8.StringAddRuntimeExtToAscii) \ SC(sub_string_runtime, V8.SubStringRuntime) \ SC(sub_string_native, V8.SubStringNative) \ SC(string_compare_native, V8.StringCompareNative) \ diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index e3d08875524..9d1aa72d5bb 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -33,9 +33,9 @@ // NOTE these macros are used by the SCons build script so their names // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 -#define MINOR_VERSION 1 -#define BUILD_NUMBER 10 -#define PATCH_LEVEL 0 +#define MINOR_VERSION 2 +#define BUILD_NUMBER 0 +#define PATCH_LEVEL 3 #define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 59a40af2a67..a87398740b5 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -323,6 +323,7 @@ TEST(Utf8Conversion) { 0xE3, 0x81, 0x85, 0x00}; // The number of bytes expected to be written for each length const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11}; + const int charLengths[12] = {0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5}; v8::Handle mixed = v8::String::New(mixed_string, 5); CHECK_EQ(10, mixed->Utf8Length()); // Try encoding the string with all capacities @@ -332,8 +333,10 @@ TEST(Utf8Conversion) { // Clear the buffer before reusing it for (int j = 0; j < 11; j++) buffer[j] = kNoChar; - int written = mixed->WriteUtf8(buffer, i); + int charsWritten; + int written = mixed->WriteUtf8(buffer, i, &charsWritten); CHECK_EQ(lengths[i], written); + CHECK_EQ(charLengths[i], charsWritten); // Check that the contents are correct for (int j = 0; j < lengths[i]; j++) CHECK_EQ(as_utf8[j], static_cast(buffer[j])); diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index d5bb0cb7646..7d0e6995288 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -388,7 +388,7 @@ '../../src/token.h', '../../src/top.cc', '../../src/top.h', - '../../src/type-info-inl.h', + '../../src/type-info.cc', '../../src/type-info.h', '../../src/unicode-inl.h', '../../src/unicode.cc', diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj index 58bf92f8ffe..5fa08f70386 100644 --- a/deps/v8/tools/visual_studio/v8_base.vcproj +++ b/deps/v8/tools/visual_studio/v8_base.vcproj @@ -945,7 +945,7 @@ > Date: Sun, 4 Apr 2010 18:58:55 -0700 Subject: [PATCH 07/73] Add buffer.copy --- src/node_buffer.cc | 52 ++++++++++++++++++++++++++++++++++++++ src/node_buffer.h | 1 + test/simple/test-buffer.js | 10 ++++++++ 3 files changed, 63 insertions(+) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index c16ead365e5..326a97ad71d 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -4,6 +4,8 @@ #include // malloc, free #include +#include // memcpy + #include // htons, htonl #include @@ -225,6 +227,55 @@ Handle Buffer::Slice(const Arguments &args) { } +// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd); +Handle Buffer::Copy(const Arguments &args) { + HandleScope scope; + + Buffer *source = ObjectWrap::Unwrap(args.This()); + + if (!Buffer::HasInstance(args[0])) { + return ThrowException(Exception::TypeError(String::New( + "First arg should be a Buffer"))); + } + + Buffer *target = ObjectWrap::Unwrap(args[0]->ToObject()); + + ssize_t target_start = args[1]->Int32Value(); + ssize_t source_start = args[2]->Int32Value(); + ssize_t source_end = args[3]->IsInt32() ? args[3]->Int32Value() + : source->length(); + + if (source_end < source_start) { + return ThrowException(Exception::Error(String::New( + "sourceEnd < sourceStart"))); + } + + if (target_start >= target->length()) { + return ThrowException(Exception::Error(String::New( + "targetStart out of bounds"))); + } + + if (source_start >= source->length()) { + return ThrowException(Exception::Error(String::New( + "sourceStart out of bounds"))); + } + + if (source_end > source->length()) { + return ThrowException(Exception::Error(String::New( + "sourceEnd out of bounds"))); + } + + ssize_t to_copy = MIN(source_end - source_start, + target->length() - target_start); + + memcpy((void*)(target->data() + target_start), + (const void*)(source->data() + source_start), + to_copy); + + return scope.Close(Integer::New(to_copy)); +} + + // var charsWritten = buffer.utf8Write(string, offset); Handle Buffer::Utf8Write(const Arguments &args) { HandleScope scope; @@ -414,6 +465,7 @@ void Buffer::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite); NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite); NODE_SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy); NODE_SET_METHOD(constructor_template->GetFunction(), "byteLength", diff --git a/src/node_buffer.h b/src/node_buffer.h index 9f497c5419f..e746cdebe18 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -53,6 +53,7 @@ class Buffer : public ObjectWrap { static v8::Handle Utf8Write(const v8::Arguments &args); static v8::Handle ByteLength(const v8::Arguments &args); static v8::Handle Unpack(const v8::Arguments &args); + static v8::Handle Copy(const v8::Arguments &args); int AsciiWrite(char *string, int offset, int length); int Utf8Write(char *string, int offset, int length); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index d175c4dfd0d..18fe7e62e84 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -17,6 +17,16 @@ for (var i = 0; i < 1024; i++) { assert.equal(i % 256, b[i]); } +var c = new Buffer(512); + +var copied = b.copy(c, 0, 0, 512); +assert.equal(512, copied); +for (var i = 0; i < c.length; i++) { + print('.'); + assert.equal(i % 256, c[i]); +} + + var asciiString = "hello world"; var offset = 100; for (var j = 0; j < 500; j++) { From ec0266a56cca10c5faa92c54baf2d3bb447ece65 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 4 Apr 2010 19:33:09 -0700 Subject: [PATCH 08/73] Update libev's clock when starting timers Make the timeouts more accurate. See test/pummel/test-timers.js --- src/node_timer.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/node_timer.cc b/src/node_timer.cc index 1c1b01ce7ad..bee1aace071 100644 --- a/src/node_timer.cc +++ b/src/node_timer.cc @@ -120,6 +120,11 @@ Timer::Start (const Arguments& args) ev_tstamp repeat = NODE_V8_UNIXTIME(args[1]); ev_timer_init(&timer->watcher_, Timer::OnTimeout, after, repeat); timer->watcher_.data = timer; + + // Update the event loop time. Need to call this because processing JS can + // take non-negligible amounts of time. + ev_now_update(EV_DEFAULT_UC); + ev_timer_start(EV_DEFAULT_UC_ &timer->watcher_); if (!was_active) timer->Ref(); From 01f7d4484e5aa079155c0affc35210eee6959f99 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 4 Apr 2010 21:12:25 -0700 Subject: [PATCH 09/73] Upgrade to WAF 1.5.15 --- bin/node-waf | 2 +- tools/waf-light | 2 +- tools/wafadmin/Build.py | 9 +++++ tools/wafadmin/Configure.py | 2 +- tools/wafadmin/Constants.py | 6 ++-- tools/wafadmin/Node.py | 7 ++-- tools/wafadmin/Runner.py | 8 +++-- tools/wafadmin/Scripting.py | 10 +++--- tools/wafadmin/Task.py | 45 +++++++++++++------------ tools/wafadmin/TaskGen.py | 3 ++ tools/wafadmin/Tools/config_c.py | 7 ++-- tools/wafadmin/Tools/d.py | 10 ++++-- tools/wafadmin/Tools/gas.py | 1 + tools/wafadmin/Tools/gnu_dirs.py | 2 +- tools/wafadmin/Tools/msvc.py | 14 ++++++-- tools/wafadmin/Tools/preproc.py | 6 +++- tools/wafadmin/Tools/python.py | 4 +-- tools/wafadmin/Tools/qt4.py | 45 ++++++++++++------------- tools/wafadmin/Tools/suncc.py | 3 +- tools/wafadmin/Tools/suncxx.py | 10 ++++-- tools/wafadmin/Tools/vala.py | 56 ++++++++++++++++++++++++++------ tools/wafadmin/Utils.py | 35 +++++++++++++------- tools/wafadmin/py3kfixes.py | 2 +- 23 files changed, 193 insertions(+), 96 deletions(-) diff --git a/bin/node-waf b/bin/node-waf index 92f7bd8c0ec..7bbd5c524ee 100755 --- a/bin/node-waf +++ b/bin/node-waf @@ -12,6 +12,6 @@ t = join(w, 'Tools') sys.path = [w, t] + sys.path import Scripting -VERSION="1.5.14" +VERSION="1.5.15" Scripting.prepare(t, os.getcwd(), VERSION, wafdir) sys.exit(0) diff --git a/tools/waf-light b/tools/waf-light index 1fb8ce4ab72..2068d4411ce 100755 --- a/tools/waf-light +++ b/tools/waf-light @@ -37,7 +37,7 @@ if 'PSYCOWAF' in os.environ: try:import psyco;psyco.full() except:pass -VERSION="1.5.14" +VERSION="1.5.15" REVISION="x" INSTALL="x" C1='x' diff --git a/tools/wafadmin/Build.py b/tools/wafadmin/Build.py index f28b80dbb61..83c044ba055 100644 --- a/tools/wafadmin/Build.py +++ b/tools/wafadmin/Build.py @@ -681,8 +681,13 @@ class BuildContext(Utils.Context): for i in xrange(len(self.task_manager.groups)): g = self.task_manager.groups[i] self.task_manager.current_group = i + if Logs.verbose: + Logs.debug('group: group %s' % ([x for x in self.task_manager.groups_names if id(self.task_manager.groups_names[x]) == id(g)][0])) + for tg in g.tasks_gen: if id(tg) in to_compile: + if Logs.verbose: + Logs.debug('group: %s' % tg) tg.post() else: @@ -702,9 +707,13 @@ class BuildContext(Utils.Context): for i in xrange(len(self.task_manager.groups)): g = self.task_manager.groups[i] self.task_manager.current_group = i + if Logs.verbose: + Logs.debug('group: group %s' % ([x for x in self.task_manager.groups_names if id(self.task_manager.groups_names[x]) == id(g)][0])) for tg in g.tasks_gen: if not tg.path.is_child_of(ln): continue + if Logs.verbose: + Logs.debug('group: %s' % tg) tg.post() def env_of_name(self, name): diff --git a/tools/wafadmin/Configure.py b/tools/wafadmin/Configure.py index 163b46dc778..7501cb10312 100644 --- a/tools/wafadmin/Configure.py +++ b/tools/wafadmin/Configure.py @@ -125,7 +125,7 @@ class ConfigurationContext(Utils.Context): except (OSError, IOError): self.fatal('could not open %r for writing' % path) - app = getattr(Utils.g_module, 'APPNAME', '') + app = Utils.g_module.APPNAME if app: ver = getattr(Utils.g_module, 'VERSION', '') if ver: diff --git a/tools/wafadmin/Constants.py b/tools/wafadmin/Constants.py index fa1a7293ad7..f1fceac634a 100644 --- a/tools/wafadmin/Constants.py +++ b/tools/wafadmin/Constants.py @@ -9,9 +9,9 @@ maintainer: the version number is updated from the top-level wscript file """ # do not touch these three lines, they are updated automatically -HEXVERSION = 0x105014 -WAFVERSION="1.5.14" -WAFREVISION = "7363M" +HEXVERSION = 0x105015 +WAFVERSION="1.5.15" +WAFREVISION = "7505M" ABI = 7 # permissions diff --git a/tools/wafadmin/Node.py b/tools/wafadmin/Node.py index 26a2113e029..47d3479864f 100644 --- a/tools/wafadmin/Node.py +++ b/tools/wafadmin/Node.py @@ -204,7 +204,7 @@ class Node(object): if node: tp = node.id & 3 if tp != BUILD: - raise Utils.WafError("find_or_declare returns a build node, not a source nor a directory %r" % lst) + raise Utils.WafError('find_or_declare cannot return a build node (build files in the source directory %r?)' % lst) return node node = self.__class__(name, parent, BUILD) return node @@ -461,8 +461,9 @@ class Node(object): "path seen from the build dir default/src/foo.cpp" if self.id & 3 == FILE: return self.relpath_gen(self.__class__.bld.bldnode) - if self.path_to_parent(self.__class__.bld.srcnode) is not '': - return os.path.join(env.variant(), self.path_to_parent(self.__class__.bld.srcnode)) + p = self.path_to_parent(self.__class__.bld.srcnode) + if p is not '': + return env.variant() + os.sep + p return env.variant() def srcpath(self, env=None): diff --git a/tools/wafadmin/Runner.py b/tools/wafadmin/Runner.py index 384b1c68c7e..5237c1abdf2 100644 --- a/tools/wafadmin/Runner.py +++ b/tools/wafadmin/Runner.py @@ -190,11 +190,15 @@ class Parallel(object): try: st = tsk.runnable_status() except Exception, e: - tsk.err_msg = Utils.ex_stack() - tsk.hasrun = EXCEPTION self.processed += 1 + if self.stop and not Options.options.keep: + tsk.hasrun = SKIPPED + self.manager.add_finished(tsk) + continue self.error_handler(tsk) self.manager.add_finished(tsk) + tsk.hasrun = EXCEPTION + tsk.err_msg = Utils.ex_stack() continue if st == ASK_LATER: diff --git a/tools/wafadmin/Scripting.py b/tools/wafadmin/Scripting.py index 203e143c2b3..e3d82c8eb9b 100644 --- a/tools/wafadmin/Scripting.py +++ b/tools/wafadmin/Scripting.py @@ -412,7 +412,7 @@ def build_impl(bld): bld.install() -excludes = '.bzr .bzrignore .git .gitignore .svn CVS .cvsignore .arch-ids {arch} SCCS BitKeeper .hg _MTN _darcs Makefile Makefile.in config.log'.split() +excludes = '.bzr .bzrignore .git .gitignore .svn CVS .cvsignore .arch-ids {arch} SCCS BitKeeper .hg _MTN _darcs Makefile Makefile.in config.log .gitattributes .hgignore .hgtags'.split() dist_exts = '~ .rej .orig .pyc .pyo .bak .tar.bz2 tar.gz .zip .swp'.split() def dont_dist(name, src, build_dir): global excludes, dist_exts @@ -486,8 +486,8 @@ def dist(appname='', version=''): # return return (distdirname, tarballname) import tarfile - if not appname: appname = getattr(Utils.g_module, APPNAME, 'noname') - if not version: version = getattr(Utils.g_module, VERSION, '1.0') + if not appname: appname = Utils.g_module.APPNAME + if not version: version = Utils.g_module.VERSION tmp_folder = appname + '-' + version if g_gz in ['gz', 'bz2']: @@ -545,8 +545,8 @@ def distcheck(appname='', version=''): '''checks if the sources compile (tarball from 'dist')''' import tempfile, tarfile - if not appname: appname = getattr(Utils.g_module, APPNAME, 'noname') - if not version: version = getattr(Utils.g_module, VERSION, '1.0') + if not appname: appname = Utils.g_module.APPNAME + if not version: version = Utils.g_module.VERSION waf = os.path.abspath(sys.argv[0]) tarball = dist(appname, version) diff --git a/tools/wafadmin/Task.py b/tools/wafadmin/Task.py index f9f16a95fa1..e6a37e91ec4 100644 --- a/tools/wafadmin/Task.py +++ b/tools/wafadmin/Task.py @@ -578,22 +578,25 @@ class Task(TaskBase): try: return self.cache_sig[0] except AttributeError: pass - m = md5() + self.m = md5() # explicit deps exp_sig = self.sig_explicit_deps() - m.update(exp_sig) - - # implicit deps - imp_sig = self.scan and self.sig_implicit_deps() or SIG_NIL - m.update(imp_sig) # env vars var_sig = self.sig_vars() - m.update(var_sig) + + # implicit deps + + imp_sig = SIG_NIL + if self.scan: + try: + imp_sig = self.sig_implicit_deps() + except ValueError: + return self.signature() # we now have the signature (first element) and the details (for debugging) - ret = m.digest() + ret = self.m.digest() self.cache_sig = (ret, exp_sig, imp_sig, var_sig) return ret @@ -771,7 +774,7 @@ class Task(TaskBase): def sig_explicit_deps(self): bld = self.generator.bld - m = md5() + up = self.m.update # the inputs for x in self.inputs + getattr(self, 'dep_nodes', []): @@ -780,7 +783,7 @@ class Task(TaskBase): variant = x.variant(self.env) try: - m.update(bld.node_sigs[variant][x.id]) + up(bld.node_sigs[variant][x.id]) except KeyError: raise Utils.WafError('Missing node signature for %r (required by %r)' % (x, self)) @@ -803,29 +806,28 @@ class Task(TaskBase): raise Utils.WafError('Missing node signature for %r (required by %r)' % (v, self)) elif hasattr(v, '__call__'): v = v() # dependency is a function, call it - m.update(v) + up(v) for x in self.deps_nodes: v = bld.node_sigs[x.variant(self.env)][x.id] - m.update(v) + up(v) - return m.digest() + return self.m.digest() def sig_vars(self): - m = md5() bld = self.generator.bld env = self.env # dependencies on the environment vars act_sig = bld.hash_env_vars(env, self.__class__.vars) - m.update(act_sig) + self.m.update(act_sig) # additional variable dependencies, if provided dep_vars = getattr(self, 'dep_vars', None) if dep_vars: - m.update(bld.hash_env_vars(env, dep_vars)) + self.m.update(bld.hash_env_vars(env, dep_vars)) - return m.digest() + return self.m.digest() #def scan(self, node): # """this method returns a tuple containing: @@ -852,6 +854,8 @@ class Task(TaskBase): return prev_sigs[2] except (KeyError, OSError): pass + del bld.task_sigs[key] + raise ValueError('rescan') # no previous run or the signature of the dependencies has changed, rescan the dependencies (nodes, names) = self.scan() @@ -878,8 +882,7 @@ class Task(TaskBase): """it is intended for .cpp and inferred .h files there is a single list (no tree traversal) this is the hot spot so ... do not touch""" - m = md5() - upd = m.update + upd = self.m.update bld = self.generator.bld tstamp = bld.node_sigs @@ -897,7 +900,7 @@ class Task(TaskBase): else: upd(tstamp[env.variant()][k.id]) - return m.digest() + return self.m.digest() def funex(c): dc = {} @@ -1132,7 +1135,7 @@ def extract_deps(tasks): except: # this is on purpose pass - variant = x.env.variant() + v = x.env.variant() key = x.unique_id() for k in x.generator.bld.node_deps.get(x.unique_id(), []): try: dep_to_task[(v, k.id)].append(x) diff --git a/tools/wafadmin/TaskGen.py b/tools/wafadmin/TaskGen.py index 2bd1ba689df..fa16b876946 100644 --- a/tools/wafadmin/TaskGen.py +++ b/tools/wafadmin/TaskGen.py @@ -527,6 +527,9 @@ def exec_rule(self): raise Utils.WafError('input file %r could not be found (%r)' % (x, self.path.abspath())) tsk.inputs.append(y) + if self.allnodes: + tsk.inputs.extend(self.allnodes) + if getattr(self, 'scan', None): cls.scan = self.scan diff --git a/tools/wafadmin/Tools/config_c.py b/tools/wafadmin/Tools/config_c.py index 6008265dda6..1a57566f857 100644 --- a/tools/wafadmin/Tools/config_c.py +++ b/tools/wafadmin/Tools/config_c.py @@ -186,7 +186,8 @@ def exec_cfg(self, kw): vars = Utils.to_list(kw['variables']) for v in vars: val = self.cmd_and_log('%s --variable=%s %s' % (kw['path'], v, kw['package']), kw).strip() - env.append_unique('%s_%s' % (uselib, v), val) + var = '%s_%s' % (uselib, v) + env[var] = val if not 'okmsg' in kw: kw['okmsg'] = 'ok' return @@ -541,10 +542,8 @@ def run_c_code(self, *k, **kw): # if we need to run the program, try to get its result if kw['execute']: - ak = {} # syntax for python < 2.5, don't touch - ak['stdout'] = ak['stderr'] = Utils.pproc.PIPE args = Utils.to_list(kw.get('exec_args', [])) - proc = Utils.pproc.Popen([lastprog], *args, **ak) + proc = Utils.pproc.Popen([lastprog] + args, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE) (out, err) = proc.communicate() w = self.log.write w(str(out)) diff --git a/tools/wafadmin/Tools/d.py b/tools/wafadmin/Tools/d.py index 4f4bddb749f..602f5af1b49 100644 --- a/tools/wafadmin/Tools/d.py +++ b/tools/wafadmin/Tools/d.py @@ -289,8 +289,8 @@ def apply_d_libs(self): # object has ancestors to process (shared libraries): add them to the end of the list if getattr(y, 'uselib_local', None): lst = y.to_list(y.uselib_local) - if 'dshlib' in y.features or 'cprogram' in y.features: - lst = [x for x in lst if not 'cstaticlib' in self.name_to_obj(x).features] + if 'dshlib' in y.features or 'dprogram' in y.features: + lst = [x for x in lst if not 'dstaticlib' in self.name_to_obj(x).features] tmp.extend(lst) # link task and flags @@ -386,6 +386,12 @@ def apply_d_vars(self): # now process the library paths # apply same path manipulation as used with import paths for path in libpaths: + if not os.path.isabs(path): + node = self.path.find_resource(path) + if not node: + raise Utils.WafError('could not find libpath %r from %r' % (path, self)) + path = node.abspath(self.env) + env.append_unique('DLINKFLAGS', libpath_st % path) # add libraries diff --git a/tools/wafadmin/Tools/gas.py b/tools/wafadmin/Tools/gas.py index fb255966980..c983b0a3959 100644 --- a/tools/wafadmin/Tools/gas.py +++ b/tools/wafadmin/Tools/gas.py @@ -34,4 +34,5 @@ def asm_incflags(self): def detect(conf): conf.find_program(['gas', 'as'], var='AS') if not conf.env.AS: conf.env.AS = conf.env.CC + #conf.env.ASFLAGS = ['-c'] <- may be necesary for .S files diff --git a/tools/wafadmin/Tools/gnu_dirs.py b/tools/wafadmin/Tools/gnu_dirs.py index 3fc452d02dd..856e4a7204b 100644 --- a/tools/wafadmin/Tools/gnu_dirs.py +++ b/tools/wafadmin/Tools/gnu_dirs.py @@ -65,7 +65,7 @@ def detect(conf): env = conf.env env['EXEC_PREFIX'] = get_param('EXEC_PREFIX', env['PREFIX']) - env['PACKAGE'] = getattr(Utils.g_module, 'APPNAME', None) or env['PACKAGE'] + env['PACKAGE'] = Utils.g_module.APPNAME complete = False iter = 0 diff --git a/tools/wafadmin/Tools/msvc.py b/tools/wafadmin/Tools/msvc.py index 64fb05bceeb..94e5da5efd5 100644 --- a/tools/wafadmin/Tools/msvc.py +++ b/tools/wafadmin/Tools/msvc.py @@ -724,7 +724,17 @@ def exec_mf(self): self.do_manifest = False outfile = self.outputs[0].bldpath(env) - manifest = self.outputs[-1].bldpath(env) + + manifest = None + for out_node in self.outputs: + if out_node.name.endswith('.manifest'): + manifest = out_node.bldpath(env) + break + if manifest is None: + # Should never get here. If we do, it means the manifest file was + # never added to the outputs list, thus we don't have a manifest file + # to embed, so we just return. + return 0 # embedding mode. Different for EXE's and DLL's. # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx @@ -738,7 +748,7 @@ def exec_mf(self): #flags = ' '.join(env['MTFLAGS'] or []) lst = [] - lst.extend(Utils.to_list(env['MT'])) + lst.extend([env['MT']]) lst.extend(Utils.to_list(env['MTFLAGS'])) lst.extend(Utils.to_list("-manifest")) lst.extend(Utils.to_list(manifest)) diff --git a/tools/wafadmin/Tools/preproc.py b/tools/wafadmin/Tools/preproc.py index 924bea2227a..1a9b0ff1555 100644 --- a/tools/wafadmin/Tools/preproc.py +++ b/tools/wafadmin/Tools/preproc.py @@ -35,6 +35,10 @@ class PreprocError(Utils.WafError): POPFILE = '-' + +recursion_limit = 100 +"do not loop too much on header inclusion" + go_absolute = 0 "set to 1 to track headers on files in /usr/include - else absolute paths are ignored" @@ -636,7 +640,7 @@ class c_parser(object): filepath = node.abspath(self.env) self.count_files += 1 - if self.count_files > 30000: raise PreprocError("recursion limit exceeded") + if self.count_files > recursion_limit: raise PreprocError("recursion limit exceeded") pc = self.parse_cache debug('preproc: reading file %r', filepath) try: diff --git a/tools/wafadmin/Tools/python.py b/tools/wafadmin/Tools/python.py index d87d1e8ac30..cfa81b0b8d1 100644 --- a/tools/wafadmin/Tools/python.py +++ b/tools/wafadmin/Tools/python.py @@ -55,7 +55,7 @@ def init_pyembed(self): @extension(EXT_PY) def process_py(self, node): - if not (self.bld.is_install or self.install_path): + if not (self.bld.is_install and self.install_path): return def inst_py(ctx): install_pyfile(self, node) @@ -122,7 +122,7 @@ def _get_python_variables(python_exe, variables, imports=['import sys']): except KeyError: pass proc = Utils.pproc.Popen([python_exe, "-c", '\n'.join(program)], stdout=Utils.pproc.PIPE, env=os_env) - output = proc.communicate()[0].split("\n") + output = proc.communicate()[0].split("\n") # do not touch, python3 if proc.returncode: if Options.options.verbose: warn("Python program to extract python configuration variables failed:\n%s" diff --git a/tools/wafadmin/Tools/qt4.py b/tools/wafadmin/Tools/qt4.py index 0a60b861230..f63365a28ed 100644 --- a/tools/wafadmin/Tools/qt4.py +++ b/tools/wafadmin/Tools/qt4.py @@ -96,31 +96,25 @@ class qxx_task(Task.Task): if d in mocfiles: error("paranoia owns") continue + # process that base.moc only once mocfiles.append(d) - # find the extension - this search is done only once - ext = '' - try: ext = Options.options.qt_header_ext - except AttributeError: pass - - if not ext: - base2 = d[:-4] - paths = [node.parent.srcpath(self.env), node.parent.bldpath(self.env)] - poss = [(x, y) for x in MOC_H for y in paths] - for (i, path) in poss: - try: - # TODO we could use find_resource - os.stat(os.path.join(path, base2+i)) - except OSError: - pass - else: - ext = i + # find the extension (performed only when the .cpp has changes) + base2 = d[:-4] + for path in [node.parent] + self.generator.env['INC_PATHS']: + tree.rescan(path) + vals = getattr(Options.options, 'qt_header_ext', '') or MOC_H + for ex in vals: + h_node = path.find_resource(base2 + ex) + if h_node: break - if not ext: raise Utils.WafError("no header found for %s which is a moc file" % str(d)) + else: + continue + break + else: + raise Utils.WafError("no header found for %s which is a moc file" % str(d)) - # next time we will not search for the extension (look at the 'for' loop below) - h_node = node.parent.find_resource(base2+i) m_node = h_node.change_ext('.moc') tree.node_deps[(self.inputs[0].parent.id, self.env.variant(), m_node.name)] = h_node @@ -246,7 +240,8 @@ def apply_qt4(self): if update: trans.append(t.inputs[0]) - if update and Options.options.trans_qt4: + trans_qt4 = getattr(Options.options, 'trans_qt4', False) + if update and trans_qt4: # we need the cpp files given, except the rcc task we create after # FIXME may be broken u = Task.TaskCmd(translation_update, self.env, 2) @@ -426,6 +421,11 @@ def detect_qt4(conf): env.append_unique(kind + 'LIB_' + uselib, lib + d + ext) conf.check_message_2('ok ' + path, 'GREEN') break + path = os.path.join(qtbin, pat % (lib + d + ext)) + if os.path.exists(path): + env.append_unique(kind + 'LIB_' + uselib, lib + d + ext) + conf.check_message_2('ok ' + path, 'GREEN') + break else: conf.check_message_2('not found', 'YELLOW') continue @@ -461,7 +461,8 @@ def detect_qt4(conf): process_lib(vars_debug, 'LIBPATH_QTCORE_DEBUG') # rpath if wanted - if Options.options.want_rpath: + want_rpath = getattr(Options.options, 'want_rpath', 1) + if want_rpath: def process_rpath(vars_, coreval): for d in vars_: var = d.upper() diff --git a/tools/wafadmin/Tools/suncc.py b/tools/wafadmin/Tools/suncc.py index 0aa430556c8..138722978aa 100644 --- a/tools/wafadmin/Tools/suncc.py +++ b/tools/wafadmin/Tools/suncc.py @@ -17,9 +17,10 @@ def find_scc(conf): #if not cc: cc = conf.find_program('gcc', var='CC') if not cc: cc = conf.find_program('cc', var='CC') if not cc: conf.fatal('suncc was not found') + cc = conf.cmd_to_list(cc) try: - if not Utils.cmd_output('%s -flags' % cc): + if not Utils.cmd_output(cc + ['-flags']): conf.fatal('suncc %r was not found' % cc) except ValueError: conf.fatal('suncc -flags could not be executed') diff --git a/tools/wafadmin/Tools/suncxx.py b/tools/wafadmin/Tools/suncxx.py index f168502e00a..b6e9ef8562a 100644 --- a/tools/wafadmin/Tools/suncxx.py +++ b/tools/wafadmin/Tools/suncxx.py @@ -14,10 +14,16 @@ def find_sxx(conf): cc = None if v['CXX']: cc = v['CXX'] elif 'CXX' in conf.environ: cc = conf.environ['CXX'] - #if not cc: cc = conf.find_program('g++', var='CXX') if not cc: cc = conf.find_program('c++', var='CXX') - if not cc: cc = conf.find_program('CC', var='CXX') #studio if not cc: conf.fatal('sunc++ was not found') + cc = conf.cmd_to_list(cc) + + try: + if not Utils.cmd_output(cc + ['-flags']): + conf.fatal('sunc++ %r was not found' % cc) + except ValueError: + conf.fatal('sunc++ -flags could not be executed') + v['CXX'] = cc v['CXX_NAME'] = 'sun' diff --git a/tools/wafadmin/Tools/vala.py b/tools/wafadmin/Tools/vala.py index 43b802c33e6..806f2f4b0f1 100644 --- a/tools/wafadmin/Tools/vala.py +++ b/tools/wafadmin/Tools/vala.py @@ -3,7 +3,7 @@ # Ali Sabil, 2007 import os.path, shutil -import Task, Runner, Utils, Logs, Build, Node +import Task, Runner, Utils, Logs, Build, Node, Options from TaskGen import extension, after, before EXT_VALA = ['.vala', '.gs'] @@ -29,6 +29,9 @@ class valac_task(Task.Task): if self.threading: cmd.append('--thread') + if self.profile: + cmd.append('--profile=%s' % self.profile) + if self.target_glib: cmd.append('--target-glib=%s' % self.target_glib) @@ -134,13 +137,15 @@ def vala_file(self, node): valatask = self.create_task('valac') self.valatask = valatask self.includes = Utils.to_list(getattr(self, 'includes', [])) + self.uselib = self.to_list(self.uselib) valatask.packages = [] valatask.packages_private = Utils.to_list(getattr(self, 'packages_private', [])) valatask.vapi_dirs = [] valatask.target = self.target valatask.threading = False valatask.install_path = self.install_path - valatask.target_glib = None + valatask.profile = getattr (self, 'profile', 'gobject') + valatask.target_glib = None #Deprecated packages = Utils.to_list(getattr(self, 'packages', [])) vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', [])) @@ -197,14 +202,24 @@ def vala_file(self, node): except AttributeError: Logs.warn("Unable to locate include directory: '%s'" % include) - if hasattr(self, 'threading'): - valatask.threading = self.threading - self.uselib = self.to_list(self.uselib) - if not 'GTHREAD' in self.uselib: - self.uselib.append('GTHREAD') + if valatask.profile == 'gobject': + if hasattr(self, 'target_glib'): + Logs.warn ('target_glib on vala tasks is deprecated --vala-target-glib=MAJOR.MINOR from the vala tool options') - if hasattr(self, 'target_glib'): - valatask.target_glib = self.target_glib + if getattr(Options.options, 'vala_target_glib', None): + valatask.target_glib = Options.options.vala_target_glib + + if not 'GOBJECT' in self.uselib: + self.uselib.append('GOBJECT') + + if hasattr(self, 'threading'): + if valatask.profile == 'gobject': + valatask.threading = self.threading + if not 'GTHREAD' in self.uselib: + self.uselib.append('GTHREAD') + else: + #Vala doesn't have threading support for dova nor posix + Logs.warn("Profile %s does not have threading support" % valatask.profile) if hasattr(self, 'gir'): valatask.gir = self.gir @@ -244,8 +259,23 @@ def detect(conf): valac = conf.find_program('valac', var='VALAC', mandatory=True) + if not conf.env["HAVE_GOBJECT"]: + pkg_args = {'package': 'gobject-2.0', + 'uselib_store': 'GOBJECT', + 'args': '--cflags --libs'} + if getattr(Options.options, 'vala_target_glib', None): + pkg_args['atleast_version'] = Options.options.vala_target_glib + + conf.check_cfg(**pkg_args) + if not conf.env["HAVE_GTHREAD"]: - conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs') + pkg_args = {'package': 'gthread-2.0', + 'uselib_store': 'GTHREAD', + 'args': '--cflags --libs'} + if getattr(Options.options, 'vala_target_glib', None): + pkg_args['atleast_version'] = Options.options.vala_target_glib + + conf.check_cfg(**pkg_args) try: output = Utils.cmd_output(valac + " --version", silent=True) @@ -269,3 +299,9 @@ def detect(conf): conf.env['VALAC_VERSION'] = valac_version conf.env['VALAFLAGS'] = '' +def set_options (opt): + valaopts = opt.add_option_group('Vala Compiler Options') + valaopts.add_option ('--vala-target-glib', default=None, + dest='vala_target_glib', metavar='MAJOR.MINOR', + help='Target version of glib for Vala GObject code generation') + diff --git a/tools/wafadmin/Utils.py b/tools/wafadmin/Utils.py index 1d1b2009c1a..e03126e8d5b 100644 --- a/tools/wafadmin/Utils.py +++ b/tools/wafadmin/Utils.py @@ -130,18 +130,22 @@ try: except ImportError: try: - from hashlib import md5 - except ImportError: - from md5 import md5 + try: + from hashlib import md5 + except ImportError: + from md5 import md5 - def h_file(filename): - f = open(filename, 'rb') - m = md5() - while (filename): - filename = f.read(100000) - m.update(filename) - f.close() - return m.digest() + def h_file(filename): + f = open(filename, 'rb') + m = md5() + while (filename): + filename = f.read(100000) + m.update(filename) + f.close() + return m.digest() + except ImportError: + # portability fixes may be added elsewhere (although, md5 should be everywhere by now) + md5 = None class ordered_dict(UserDict): def __init__(self, dict = None): @@ -282,6 +286,15 @@ def set_main_module(file_path): g_module = load_module(file_path, 'wscript_main') g_module.root_path = file_path + try: + g_module.APPNAME + except: + g_module.APPNAME = 'noname' + try: + g_module.VERSION + except: + g_module.VERSION = '1.0' + # note: to register the module globally, use the following: # sys.modules['wscript_main'] = g_module diff --git a/tools/wafadmin/py3kfixes.py b/tools/wafadmin/py3kfixes.py index ebfeaae77fe..6aeb26b64ae 100644 --- a/tools/wafadmin/py3kfixes.py +++ b/tools/wafadmin/py3kfixes.py @@ -100,7 +100,7 @@ def r7(code): @subst('Tools/python.py') def r8(code): - code = code.replace('p.communicate()[0]', 'p.communicate()[0].decode("utf-8")') + code = code.replace('proc.communicate()[0]', 'proc.communicate()[0].decode("utf-8")') return code @subst('Tools/glib2.py') From 85487c82d0bc187398b0168d1ac9607f51e76867 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 4 Apr 2010 21:37:06 -0700 Subject: [PATCH 10/73] Blob struct should not contain actual data This is to allow eventual realloc without messing up the data_ references in all the slices. --- src/node_buffer.cc | 51 ++++++++++++++++++++++++++++------------------ src/node_buffer.h | 6 +++--- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 326a97ad71d..813f5657ede 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -47,19 +47,24 @@ Persistent Buffer::constructor_template; struct Blob_ { unsigned int refs; size_t length; - char data[1]; + char *data; }; typedef struct Blob_ Blob; static inline Blob * blob_new(size_t length) { - size_t s = sizeof(Blob) - 1 + length; - Blob * blob = (Blob*) malloc(s); + Blob * blob = (Blob*) malloc(sizeof(Blob)); if (!blob) return NULL; - V8::AdjustAmountOfExternalAllocatedMemory(s); + + blob->data = (char*) malloc(length); + if (!blob->data) { + free(blob); + return NULL; + } + + V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Blob) + length); blob->length = length; blob->refs = 0; - //fprintf(stderr, "alloc %d bytes\n", length); return blob; } @@ -73,8 +78,8 @@ static inline void blob_unref(Blob *blob) { assert(blob->refs > 0); if (--blob->refs == 0) { //fprintf(stderr, "free %d bytes\n", blob->length); - size_t s = sizeof(Blob) - 1 + blob->length; - V8::AdjustAmountOfExternalAllocatedMemory(-s); + V8::AdjustAmountOfExternalAllocatedMemory(-(sizeof(Blob) + blob->length)); + free(blob->data); free(blob); } } @@ -133,9 +138,9 @@ Handle Buffer::New(const Arguments &args) { } buffer->Wrap(args.This()); - args.This()->SetIndexedPropertiesToExternalArrayData((void*)buffer->data_, + args.This()->SetIndexedPropertiesToExternalArrayData(buffer->data(), kExternalUnsignedByteArray, - buffer->length_); + buffer->length()); args.This()->Set(length_symbol, Integer::New(buffer->length_)); return args.This(); } @@ -143,8 +148,9 @@ Handle Buffer::New(const Arguments &args) { Buffer::Buffer(size_t length) : ObjectWrap() { blob_ = blob_new(length); + off_ = 0; length_ = length; - data_ = blob_->data; + blob_ref(blob_); V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer)); @@ -157,9 +163,9 @@ Buffer::Buffer(Buffer *parent, size_t start, size_t end) : ObjectWrap() { blob_ref(blob_); assert(start <= end); + off_ = start; length_ = end - start; assert(length_ <= parent->length_); - data_ = parent->data_ + start; V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer)); } @@ -173,12 +179,17 @@ Buffer::~Buffer() { } +char* Buffer::data() { + return blob_->data + off_; +} + + Handle Buffer::BinarySlice(const Arguments &args) { HandleScope scope; Buffer *parent = ObjectWrap::Unwrap(args.This()); SLICE_ARGS(args[0], args[1]) - const char *data = const_cast(parent->data_ + start); + const char *data = const_cast(parent->data() + start); //Local string = String::New(data, end - start); Local b = Encode(data, end - start, BINARY); @@ -200,7 +211,7 @@ Handle Buffer::AsciiSlice(const Arguments &args) { assert(parent->blob_->refs >= 2); #endif - const char *data = const_cast(parent->data_ + start); + const char *data = const_cast(parent->data() + start); Local string = String::New(data, end - start); @@ -212,7 +223,7 @@ Handle Buffer::Utf8Slice(const Arguments &args) { HandleScope scope; Buffer *parent = ObjectWrap::Unwrap(args.This()); SLICE_ARGS(args[0], args[1]) - const char *data = const_cast(parent->data_ + start); + const char *data = const_cast(parent->data() + start); Local string = String::New(data, end - start); return scope.Close(string); } @@ -295,7 +306,7 @@ Handle Buffer::Utf8Write(const Arguments &args) { "Offset is out of bounds"))); } - const char *p = buffer->data_ + offset; + const char *p = buffer->data() + offset; int written = s->WriteUtf8((char*)p, buffer->length_ - offset); @@ -323,7 +334,7 @@ Handle Buffer::AsciiWrite(const Arguments &args) { "Offset is out of bounds"))); } - const char *p = buffer->data_ + offset; + const char *p = buffer->data() + offset; size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset); @@ -351,7 +362,7 @@ Handle Buffer::BinaryWrite(const Arguments &args) { "Offset is out of bounds"))); } - char *p = (char*)buffer->data_ + offset; + char *p = (char*)buffer->data() + offset; size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset); @@ -393,7 +404,7 @@ Handle Buffer::Unpack(const Arguments &args) { // 32bit unsigned integer in network byte order case 'N': if (index + 3 >= buffer->length_) return OUT_OF_BOUNDS; - uint32 = htonl(*(uint32_t*)(buffer->data_ + index)); + uint32 = htonl(*(uint32_t*)(buffer->data() + index)); array->Set(Integer::New(i), Integer::NewFromUnsigned(uint32)); index += 4; break; @@ -401,7 +412,7 @@ Handle Buffer::Unpack(const Arguments &args) { // 16bit unsigned integer in network byte order case 'n': if (index + 1 >= buffer->length_) return OUT_OF_BOUNDS; - uint16 = htons(*(uint16_t*)(buffer->data_ + index)); + uint16 = htons(*(uint16_t*)(buffer->data() + index)); array->Set(Integer::New(i), Integer::NewFromUnsigned(uint16)); index += 2; break; @@ -409,7 +420,7 @@ Handle Buffer::Unpack(const Arguments &args) { // a single octet, unsigned. case 'o': if (index >= buffer->length_) return OUT_OF_BOUNDS; - uint8 = (uint8_t)buffer->data_[index]; + uint8 = (uint8_t)buffer->data()[index]; array->Set(Integer::New(i), Integer::NewFromUnsigned(uint8)); index += 1; break; diff --git a/src/node_buffer.h b/src/node_buffer.h index e746cdebe18..24ead8701a5 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -37,7 +37,7 @@ class Buffer : public ObjectWrap { return constructor_template->HasInstance(obj); } - const char* data() const { return data_; } + char* data(); size_t length() const { return length_; } struct Blob_* blob() const { return blob_; } @@ -63,8 +63,8 @@ class Buffer : public ObjectWrap { Buffer(Buffer *parent, size_t start, size_t end); ~Buffer(); - const char *data_; - size_t length_; + size_t off_; // offset inside blob_ + size_t length_; // length inside blob_ struct Blob_ *blob_; }; From b0d1d6c2b905e03f910f611fe5f916b30164d9b2 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 4 Apr 2010 22:51:27 -0700 Subject: [PATCH 11/73] Reset stdin, stdout fd flags on exit In vim, lauching node as a child process would mess up the screen. This was because Node was changing the flags on STDIN_FILENO and STDOUT_FILENO (particularly adding O_NONBLOCK) but those flags leaked into the parent process. --- src/node_stdio.cc | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/node_stdio.cc b/src/node_stdio.cc index ee1278f4bb9..7af086ddbbf 100644 --- a/src/node_stdio.cc +++ b/src/node_stdio.cc @@ -17,6 +17,9 @@ static struct coupling *stdout_coupling = NULL; static int stdin_fd = -1; static int stdout_fd = -1; +static int stdout_flags = -1; +static int stdin_flags = -1; + static Local errno_exception(int errorno) { Local e = Exception::Error(String::NewSymbol(strerror(errorno))); @@ -55,17 +58,6 @@ WriteError (const Arguments& args) } -static inline int SetNonblock(int fd) { - int flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) return -1; - - int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (r == -1) return -1; - - return 0; -} - - static Handle OpenStdin(const Arguments& args) { HandleScope scope; @@ -81,14 +73,33 @@ static Handle OpenStdin(const Arguments& args) { stdin_coupling = coupling_new_pull(STDIN_FILENO); stdin_fd = coupling_nonblocking_fd(stdin_coupling); } - SetNonblock(stdin_fd); + + stdin_flags = fcntl(stdin_fd, F_GETFL, 0); + if (stdin_flags == -1) { + // TODO DRY + return ThrowException(Exception::Error(String::New("fcntl error!"))); + } + + int r = fcntl(stdin_fd, F_SETFL, stdin_flags | O_NONBLOCK); + if (r == -1) { + // TODO DRY + return ThrowException(Exception::Error(String::New("fcntl error!"))); + } return scope.Close(Integer::New(stdin_fd)); } void Stdio::Flush() { + if (stdin_flags != -1) { + fcntl(stdin_fd, F_SETFL, stdin_flags & ~O_NONBLOCK); + } + if (stdout_fd >= 0) { + if (stdout_flags != -1) { + fcntl(stdout_fd, F_SETFL, stdout_flags & ~O_NONBLOCK); + } + close(stdout_fd); stdout_fd = -1; } @@ -112,7 +123,10 @@ void Stdio::Initialize(v8::Handle target) { stdout_coupling = coupling_new_push(STDOUT_FILENO); stdout_fd = coupling_nonblocking_fd(stdout_coupling); } - SetNonblock(stdout_fd); + + stdout_flags = fcntl(stdout_fd, F_GETFL, 0); + + int r = fcntl(stdout_fd, F_SETFL, stdout_flags | O_NONBLOCK); target->Set(String::NewSymbol("stdoutFD"), Integer::New(stdout_fd)); From 0301adf9b44a966ba0d2503ab79a6583e7f6436b Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 5 Apr 2010 11:32:18 -0700 Subject: [PATCH 12/73] In tests, wait for 'listening' before connecting --- test/pummel/test-keep-alive.js | 20 +++++++++++--------- test/simple/test-http-cat.js | 32 +++++++++++++++++--------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/test/pummel/test-keep-alive.js b/test/pummel/test-keep-alive.js index d52f06659b1..5b71d4b00a4 100644 --- a/test/pummel/test-keep-alive.js +++ b/test/pummel/test-keep-alive.js @@ -42,16 +42,18 @@ function runAb(opts, callback) { }); } -runAb("-k -c 100 -t 2", function (reqSec, keepAliveRequests) { - keepAliveReqSec = reqSec; - assert.equal(true, keepAliveRequests > 0); - puts("keep-alive: " + keepAliveReqSec + " req/sec"); +server.addListener('listening', function () { + runAb("-k -c 100 -t 2", function (reqSec, keepAliveRequests) { + keepAliveReqSec = reqSec; + assert.equal(true, keepAliveRequests > 0); + puts("keep-alive: " + keepAliveReqSec + " req/sec"); - runAb("-c 100 -t 2", function (reqSec, keepAliveRequests) { - normalReqSec = reqSec; - assert.equal(0, keepAliveRequests); - puts("normal: " + normalReqSec + " req/sec"); - server.close(); + runAb("-c 100 -t 2", function (reqSec, keepAliveRequests) { + normalReqSec = reqSec; + assert.equal(0, keepAliveRequests); + puts("normal: " + normalReqSec + " req/sec"); + server.close(); + }); }); }); diff --git a/test/simple/test-http-cat.js b/test/simple/test-http-cat.js index e81a5c502fe..f333b5e7d9a 100644 --- a/test/simple/test-http-cat.js +++ b/test/simple/test-http-cat.js @@ -16,22 +16,24 @@ server.listen(PORT); var got_good_server_content = false; var bad_server_got_error = false; -http.cat("http://localhost:"+PORT+"/", "utf8", function (err, content) { - if (err) { - throw err; - } else { - puts("got response"); - got_good_server_content = true; - assert.equal(body, content); - server.close(); - } -}); +server.addListener('listening', function () { + http.cat("http://localhost:"+PORT+"/", "utf8", function (err, content) { + if (err) { + throw err; + } else { + puts("got response"); + got_good_server_content = true; + assert.equal(body, content); + server.close(); + } + }); -http.cat("http://localhost:12312/", "utf8", function (err, content) { - if (err) { - puts("got error (this should happen)"); - bad_server_got_error = true; - } + http.cat("http://localhost:12312/", "utf8", function (err, content) { + if (err) { + puts("got error (this should happen)"); + bad_server_got_error = true; + } + }); }); process.addListener("exit", function () { From 801fb8a614aeafb05235527557d762068e74e6ff Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 5 Apr 2010 13:51:32 -0700 Subject: [PATCH 13/73] Better, faster, idle notification --- src/node.cc | 99 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 13 deletions(-) diff --git a/src/node.cc b/src/node.cc index 99852cecf12..63be87f5f90 100644 --- a/src/node.cc +++ b/src/node.cc @@ -76,17 +76,89 @@ static ev_async eio_want_poll_notifier; static ev_async eio_done_poll_notifier; static ev_idle eio_poller; +// We need to notify V8 when we're idle so that it can run the garbage +// collector. The interface to this is V8::IdleNotification(). It returns +// true if the heap hasn't be fully compacted, and needs to be run again. +// Returning false means that it doesn't have anymore work to do. +// +// We try to wait for a period of GC_INTERVAL (2 seconds) of idleness, where +// idleness means that no libev watchers have been executed. Since +// everything in node uses libev watchers, this is a pretty good measure of +// idleness. This is done with gc_check, which records the timestamp +// last_active on every tick of the event loop, and with gc_timer which +// executes every few seconds to measure if +// last_active + GC_INTERVAL < ev_now() +// If we do find a period of idleness, then we start the gc_idle timer which +// will very repaidly call IdleNotification until the heap is fully +// compacted. +static ev_tstamp last_active; static ev_timer gc_timer; +static ev_check gc_check; +static ev_idle gc_idle; +static bool needs_gc; #define GC_INTERVAL 2.0 -// Node calls this every GC_INTERVAL seconds in order to try and call the -// GC. This watcher is run with maximum priority, so ev_pending_count() == 0 -// is an effective measure of idleness. -static void GCTimeout(EV_P_ ev_timer *watcher, int revents) { +static void CheckIdleness(EV_P_ ev_timer *watcher, int revents) { assert(watcher == &gc_timer); assert(revents == EV_TIMER); - if (ev_pending_count(EV_DEFAULT_UC) == 0) V8::IdleNotification(); + + //fprintf(stderr, "check idle\n"); + + ev_tstamp idle_time = ev_now() - last_active; + + if (idle_time > GC_INTERVAL) { + if (needs_gc) { + needs_gc = false; + if (!V8::IdleNotification()) { + ev_idle_start(EV_DEFAULT_UC_ &gc_idle); + } + } + // reset the timer + gc_timer.repeat = GC_INTERVAL; + ev_timer_again(EV_DEFAULT_UC_ watcher); + } +} + + +static void NotifyIdleness(EV_P_ ev_idle *watcher, int revents) { + assert(watcher == &gc_idle); + assert(revents == EV_IDLE); + + //fprintf(stderr, "notify idle\n"); + + if (V8::IdleNotification()) { + ev_idle_stop(EV_A_ watcher); + } + needs_gc = false; +} + + +static void Activity(EV_P_ ev_check *watcher, int revents) { + assert(watcher == &gc_check); + assert(revents == EV_CHECK); + + int pending = ev_pending_count(EV_DEFAULT_UC); + + // Don't count GC watchers as activity. + + pending -= ev_is_pending(&gc_timer); + pending -= ev_is_pending(&gc_idle); + //if (ev_is_pending(&gc_check)) pending--; // This probably never happens? + + //fprintf(stderr, "activity, pending: %d\n", pending); + + if (pending) { + last_active = ev_now(); + ev_idle_stop(EV_DEFAULT_UC_ &gc_idle); + + if (!needs_gc) { + gc_timer.repeat = GC_INTERVAL; + ev_timer_again(EV_DEFAULT_UC_ &gc_timer); + } + + needs_gc = true; + } } @@ -1460,16 +1532,17 @@ int main(int argc, char *argv[]) { #endif - ev_timer_init(&node::gc_timer, node::GCTimeout, GC_INTERVAL, GC_INTERVAL); - // Set the gc_timer to max priority so that it runs before all other - // watchers. In this way it can check if the 'tick' has other pending - // watchers by using ev_pending_count() - if it ran with lower priority - // then the other watchers might run before it - not giving us good idea - // of loop idleness. - ev_set_priority(&node::gc_timer, EV_MAXPRI); - ev_timer_start(EV_DEFAULT_UC_ &node::gc_timer); + ev_init(&node::gc_timer, node::CheckIdleness); + node::gc_timer.repeat = GC_INTERVAL; + ev_timer_again(EV_DEFAULT_UC_ &node::gc_timer); ev_unref(EV_DEFAULT_UC); + ev_check_init(&node::gc_check, node::Activity); + ev_check_start(EV_DEFAULT_UC_ &node::gc_check); + ev_unref(EV_DEFAULT_UC); + + ev_idle_init(&node::gc_idle, node::NotifyIdleness); + // Setup the EIO thread pool { // It requires 3, yes 3, watchers. From 1b758ef268c1b83c8c838b2cac10f174a78c3064 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 5 Apr 2010 16:50:05 -0700 Subject: [PATCH 14/73] Allow stream to write on close --- benchmark/http_simple.js | 3 +-- doc/index.html | 3 +-- lib/http.js | 3 ++- lib/net.js | 3 ++- test/simple/test-http-1.0.js | 3 +-- test/simple/test-http-cat.js | 3 +-- test/simple/test-http-chunked.js | 3 +-- test/simple/test-http-client-race.js | 3 +-- 8 files changed, 10 insertions(+), 14 deletions(-) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 40515779928..99685f78ab2 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -49,6 +49,5 @@ http.createServer(function (req, res) { , "Content-Length": content_length } ); - res.write(body); - res.close(); + res.close(body, 'ascii'); }).listen(8000); diff --git a/doc/index.html b/doc/index.html index e93e036cedb..7c5f81fef19 100644 --- a/doc/index.html +++ b/doc/index.html @@ -47,8 +47,7 @@ var sys = require('sys'), http.createServer(function (req, res) { setTimeout(function () { res.writeHead(200, {'Content-Type': 'text/plain'}); - res.write('Hello World'); - res.close(); + res.close('Hello World'); }, 2000); }).listen(8000); sys.puts('Server running at http://127.0.0.1:8000/'); diff --git a/lib/http.js b/lib/http.js index da957eaece4..353c7daa79f 100644 --- a/lib/http.js +++ b/lib/http.js @@ -372,7 +372,8 @@ OutgoingMessage.prototype.finish = function () { throw new Error("finish() has been renamed to close()."); }; -OutgoingMessage.prototype.close = function () { +OutgoingMessage.prototype.close = function (data, encoding) { + if (data) this.write(data, encoding); if (this.chunkedEncoding) this._send("0\r\n\r\n"); // last chunk this.finished = true; this.flush(); diff --git a/lib/net.js b/lib/net.js index 41f2be08c6b..0e04cc45ad7 100644 --- a/lib/net.js +++ b/lib/net.js @@ -713,7 +713,8 @@ Stream.prototype._shutdown = function () { }; -Stream.prototype.close = function () { +Stream.prototype.close = function (data, encoding) { + if (data) this.write(data, encoding); if (this.writable) { if (this._writeQueueLast() != END_OF_FILE) { this._writeQueue.push(END_OF_FILE); diff --git a/test/simple/test-http-1.0.js b/test/simple/test-http-1.0.js index 105acdcd8ba..3a8cd0ebb82 100644 --- a/test/simple/test-http-1.0.js +++ b/test/simple/test-http-1.0.js @@ -8,8 +8,7 @@ var client_got_eof = false; var server = http.createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"}); - res.write(body); - res.close(); + res.close(body); }) server.listen(PORT); diff --git a/test/simple/test-http-cat.js b/test/simple/test-http-cat.js index f333b5e7d9a..f270ca92782 100644 --- a/test/simple/test-http-cat.js +++ b/test/simple/test-http-cat.js @@ -8,8 +8,7 @@ var server = http.createServer(function (req, res) { ["Content-Length", body.length], ["Content-Type", "text/plain"] ]); - res.write(body); - res.close(); + res.close(body); }); server.listen(PORT); diff --git a/test/simple/test-http-chunked.js b/test/simple/test-http-chunked.js index a3395fcb9cb..bb065de938b 100644 --- a/test/simple/test-http-chunked.js +++ b/test/simple/test-http-chunked.js @@ -5,8 +5,7 @@ var UTF8_STRING = "南越国是前203年至前111年存在于岭南地区的一 var server = http.createServer(function(req, res) { res.writeHead(200, {"Content-Type": "text/plain; charset=utf8"}); - res.write(UTF8_STRING, 'utf8'); - res.close(); + res.close(UTF8_STRING, 'utf8'); }); server.listen(PORT); diff --git a/test/simple/test-http-client-race.js b/test/simple/test-http-client-race.js index 9076924b37e..b9b0df48487 100644 --- a/test/simple/test-http-client-race.js +++ b/test/simple/test-http-client-race.js @@ -10,8 +10,7 @@ var server = http.createServer(function (req, res) { res.writeHead(200, { "Content-Type": "text/plain" , "Content-Length": body.length }); - res.write(body); - res.close(); + res.close(body); }); server.listen(PORT); From 4befe93a4b4373cf2c3171d94e60a99bac854ee8 Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 22 Mar 2010 15:25:12 -0700 Subject: [PATCH 15/73] Add ini.stringify functionality, a test, and some TODOs in ini.js --- lib/ini.js | 37 +++++++++++++++++++++ test/simple/test-ini.js | 71 ++++++++++++++++++++++++----------------- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/lib/ini.js b/lib/ini.js index bc1938733b4..3a59457c605 100644 --- a/lib/ini.js +++ b/lib/ini.js @@ -1,3 +1,13 @@ +// TODO: +// 1. Handle quoted strings, including line breaks, so that this: +// foo = "bar +// baz" +// parses to {foo:"bar\n baz"} +// 2. Escape with \, so that this: +// foo = bar\ +// \"baz +// parses to {foo:"bar\n \"baz"} + exports.parse = function(d) { var ini = {'-':{}}; @@ -26,4 +36,31 @@ exports.parse = function(d) { } return ini; +}; + +function safe (val) { + return (val+"").replace(/[\n\r]+/g, " "); } + +exports.stringify = function (obj) { + // if the obj has a "-" section, then do that first. + var ini = ""; + if ("-" in obj) { + for (var key in obj["-"]) { + ini += safe(key)+" = "+safe(obj["-"][key])+"\n"; + } + } + for (var section in obj) if (section !== "-") { + ini += "[" + safe(section) + "]\n"; + for (var key in obj[section]) { + + ini += safe(key) + ((obj[section][key] === true) + ? "\n" + : " = "+safe(obj[section][key])+"\n"); + } + } + return ini; +}; + +exports.encode = exports.stringify; +exports.decode = exports.parse; diff --git a/test/simple/test-ini.js b/test/simple/test-ini.js index 9b072f27ebc..489950daffa 100644 --- a/test/simple/test-ini.js +++ b/test/simple/test-ini.js @@ -1,7 +1,8 @@ require("../common"); -var path = require('path'); -var fs = require("fs"); -parse = require("ini").parse; +var path = require('path'), + fs = require("fs"), + ini = require("ini"), + parse = require("ini").parse; debug("load fixtures/fixture.ini"); @@ -15,32 +16,44 @@ fs.readFile(p,function(err, data) { var iniContents = parse(data); assert.equal(typeof iniContents, 'object'); - var expect = - { "-" : - { "root" : "something" - , "url" : "http://example.com/?foo=bar" - } - , "the section with whitespace" : - { "this has whitespace" : "yep" - , "just a flag, no value." : true - } - , "section" : - { "one" : "two" - , "Foo" : "Bar" - , "this" : "Your Mother!" - , "blank" : "" - } - , "Section Two" : - { "something else" : "blah" - , "remove" : "whitespace" - } - }; - + var expect = { "-" : + { "root" : "something" + , "url" : "http://example.com/?foo=bar" + } + , "the section with whitespace" : + { "this has whitespace" : "yep" + , "just a flag, no value." : true + } + , "section" : + { "one" : "two" + , "Foo" : "Bar" + , "this" : "Your Mother!" + , "blank" : "" + } + , "Section Two" : + { "something else" : "blah" + , "remove" : "whitespace" + } + }, + expectStr = "root = something\n"+ + "url = http://example.com/?foo=bar\n"+ + "[the section with whitespace]\n"+ + "this has whitespace = yep\n"+ + "just a flag, no value.\n"+ + "[section]\n"+ + "one = two\n"+ + "Foo = Bar\n"+ + "this = Your Mother!\n"+ + "blank = \n"+ + "[Section Two]\n"+ + "something else = blah\n"+ + "remove = whitespace\n"; + assert.deepEqual(iniContents, expect, - "actual: \n"+inspect(iniContents) +"\n≠\nexpected:\n"+inspect(expect)) - - assert.equal(iniContents['-']['root'],'something'); - assert.equal(iniContents['section']['blank'],''); - assert.equal(iniContents['Section Two']['remove'],'whitespace'); + "actual: \n"+inspect(iniContents) +"\n≠\nexpected:\n"+inspect(expect)); + assert.equal(ini.stringify(iniContents), expectStr, + "actual: \n"+inspect(ini.stringify(iniContents)) +"\n≠\nexpected:\n"+inspect(expectStr)); }); + + From 53dd9fe200d7cd1d6f3e5c5a96891b778303be37 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 5 Apr 2010 17:54:48 -0700 Subject: [PATCH 16/73] Fix bug in buffer.utf8Write() which included \u0000 --- lib/net.js | 2 -- src/node_buffer.cc | 2 ++ test/simple/test-buffer.js | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/net.js b/lib/net.js index 0e04cc45ad7..58da9f735f9 100644 --- a/lib/net.js +++ b/lib/net.js @@ -453,8 +453,6 @@ Stream.prototype._writeOut = function (data, encoding) { } else { // default to utf8 bytesWritten = pool.utf8Write(data, pool.used); - // Don't include the null - if (pool[pool.used + bytesWritten-1] == 0) bytesWritten--; // XXX Hacky way to find out the number of characters written. // Waiting for a more optimal way: http://codereview.chromium.org/1539013 var _s = pool.utf8Slice(pool.used, pool.used + bytesWritten); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 813f5657ede..7c32d6ec60f 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -310,6 +310,8 @@ Handle Buffer::Utf8Write(const Arguments &args) { int written = s->WriteUtf8((char*)p, buffer->length_ - offset); + if (written > 0 && p[written-1] == '\0') written--; + return scope.Close(Integer::New(written)); } diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 18fe7e62e84..88282c5b0a0 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -84,3 +84,14 @@ b[6] = 0xBE; b[7] = 0xEF; assert.deepEqual([0xDEADBEEF], b.unpack('N', 4)); + + +// Bug regression test +var testValue = '\u00F6\u65E5\u672C\u8A9E'; // ö日本語 +var buffer = new Buffer(32); +var size = buffer.utf8Write(testValue, 0); +puts('bytes written to buffer: ' + size); +var slice = buffer.utf8Slice(0, size); +assert.equal(slice, testValue); + + From d7a450105778016c27446ab254dd579dbc509ad5 Mon Sep 17 00:00:00 2001 From: Vanilla Hsu Date: Wed, 7 Apr 2010 00:07:10 +0800 Subject: [PATCH 17/73] freebsd install execinfo's header to /usr/local, add it to include path. --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index aa1be930363..912cf20e9f3 100644 --- a/wscript +++ b/wscript @@ -128,7 +128,7 @@ def configure(conf): if Options.options.efence: conf.check(lib='efence', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='EFENCE') - if not conf.check(lib="execinfo", libpath=['/usr/lib', '/usr/local/lib'], uselib_store="EXECINFO"): + if not conf.check(lib="execinfo", includes=['/usr/include', '/usr/local/include'], libpath=['/usr/lib', '/usr/local/lib'], uselib_store="EXECINFO"): # Note on Darwin/OS X: This will fail, but will still be used as the # execinfo stuff are part of the standard library. if sys.platform.startswith("freebsd"): From ca0038bf2f077ed3db186866befb97bdc5c4c14f Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 6 Apr 2010 15:23:42 -0700 Subject: [PATCH 18/73] Add mising EV_DEFAULT_UC in ev_now() --- src/node.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node.cc b/src/node.cc index 63be87f5f90..5dacd68b978 100644 --- a/src/node.cc +++ b/src/node.cc @@ -105,7 +105,7 @@ static void CheckIdleness(EV_P_ ev_timer *watcher, int revents) { //fprintf(stderr, "check idle\n"); - ev_tstamp idle_time = ev_now() - last_active; + ev_tstamp idle_time = ev_now(EV_DEFAULT_UC) - last_active; if (idle_time > GC_INTERVAL) { if (needs_gc) { @@ -149,7 +149,7 @@ static void Activity(EV_P_ ev_check *watcher, int revents) { //fprintf(stderr, "activity, pending: %d\n", pending); if (pending) { - last_active = ev_now(); + last_active = ev_now(EV_DEFAULT_UC); ev_idle_stop(EV_DEFAULT_UC_ &gc_idle); if (!needs_gc) { From 38041fcaa023e60fcec1373bf909f67f321aa775 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 6 Apr 2010 16:15:04 -0700 Subject: [PATCH 19/73] Try out Flatten API Speeds up WriteUtf8 significantly when dealing with strings made by the concatenation of many others. --- deps/v8/include/v8.h | 7 +++++++ deps/v8/src/api.cc | 7 +++++++ deps/v8/test/cctest/test-strings.cc | 25 +++++++++++++++++++++++++ src/node.cc | 1 + src/node_buffer.cc | 2 ++ 5 files changed, 42 insertions(+) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 90c43831f41..c4b4db5001b 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -865,6 +865,13 @@ class V8EXPORT String : public Primitive { int length = -1, int* nchars = NULL) const; // UTF-8 + /** + * Flatten internal memory. Operations on the string tend to run faster + * after flattening especially if the string is a concatenation of many + * others. + */ + void Flatten(); + /** * A zero length string. */ diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 3ba22d63ea6..ed48503e24a 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -2731,6 +2731,13 @@ int String::Write(uint16_t* buffer, int start, int length) const { } +void v8::String::Flatten() { + EnsureInitialized("v8::String::Flatten()"); + i::Handle str = Utils::OpenHandle(this); + i::FlattenString(str); +} + + bool v8::String::IsExternal() const { EnsureInitialized("v8::String::IsExternal()"); i::Handle str = Utils::OpenHandle(this); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index a87398740b5..b6eed3c361e 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -347,6 +347,31 @@ TEST(Utf8Conversion) { } +TEST(StringConcatFlatten) { + InitializeVM(); + v8::HandleScope handle_scope; + + const char* stringA = "abc"; + const char* stringB = "def"; + + v8::Local a = v8::String::New(stringA); + v8::Local b = v8::String::New(stringB); + + v8::Local cons = v8::String::Concat(a,b); + cons->Flatten(); + + char buffer[7]; + cons->WriteUtf8(buffer); + + int i; + for (i = 0; i < 3; i++) + CHECK_EQ(stringA[i], buffer[i]); + + for (i = 0; i < 3; i++) + CHECK_EQ(stringB[i], buffer[i+3]); +} + + TEST(ExternalShortStringAdd) { ZoneScope zone(DELETE_ON_EXIT); diff --git a/src/node.cc b/src/node.cc index 5dacd68b978..71405018ae6 100644 --- a/src/node.cc +++ b/src/node.cc @@ -327,6 +327,7 @@ ssize_t DecodeWrite(char *buf, uint16_t * twobytebuf = new uint16_t[buflen]; + str->Flatten(); str->Write(twobytebuf, 0, buflen); for (size_t i = 0; i < buflen; i++) { diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 7c32d6ec60f..f524778f464 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -308,6 +308,7 @@ Handle Buffer::Utf8Write(const Arguments &args) { const char *p = buffer->data() + offset; + s->Flatten(); int written = s->WriteUtf8((char*)p, buffer->length_ - offset); if (written > 0 && p[written-1] == '\0') written--; @@ -340,6 +341,7 @@ Handle Buffer::AsciiWrite(const Arguments &args) { size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset); + s->Flatten(); int written = s->WriteAscii((char*)p, 0, towrite); return scope.Close(Integer::New(written)); } From 25adb2eb55ea46b25b9ddbe8f1e0208ea6b61d1f Mon Sep 17 00:00:00 2001 From: Vanilla Hsu Date: Wed, 7 Apr 2010 11:39:29 +0800 Subject: [PATCH 20/73] [FreeBSD] use /dev/null instead /dev/mem Without this patch, Node needs to setgid kmem when run as normal user. --- src/node.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index 71405018ae6..3da989c00f7 100644 --- a/src/node.cc +++ b/src/node.cc @@ -673,6 +673,7 @@ int getmem(size_t *rss, size_t *vsize) { #include #include #include +#include #include #include @@ -685,7 +686,7 @@ int getmem(size_t *rss, size_t *vsize) { pid = getpid(); - kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open"); + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); if (kd == NULL) goto error; kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); From e9a116fe02ef77c6e809a788cde89a2e18b55f39 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 6 Apr 2010 06:41:32 -0400 Subject: [PATCH 21/73] Include c-ares in deps/ --- deps/c-ares/AUTHORS | 37 + deps/c-ares/CHANGES | 1156 +++++++++++++++++++ deps/c-ares/NEWS | 21 + deps/c-ares/README | 60 + deps/c-ares/README.cares | 13 + deps/c-ares/README.msvc | 119 ++ deps/c-ares/README.node | 21 + deps/c-ares/RELEASE-NOTES | 18 + deps/c-ares/TODO | 23 + deps/c-ares/ares.h | 509 +++++++++ deps/c-ares/ares__close_sockets.c | 67 ++ deps/c-ares/ares__get_hostent.c | 264 +++++ deps/c-ares/ares__read_line.c | 72 ++ deps/c-ares/ares__timeval.c | 112 ++ deps/c-ares/ares_cancel.c | 64 ++ deps/c-ares/ares_data.c | 176 +++ deps/c-ares/ares_data.h | 64 ++ deps/c-ares/ares_destroy.c | 106 ++ deps/c-ares/ares_dns.h | 91 ++ deps/c-ares/ares_expand_name.c | 194 ++++ deps/c-ares/ares_expand_string.c | 76 ++ deps/c-ares/ares_fds.c | 63 ++ deps/c-ares/ares_free_hostent.c | 40 + deps/c-ares/ares_free_string.c | 26 + deps/c-ares/ares_gethostbyaddr.c | 291 +++++ deps/c-ares/ares_gethostbyname.c | 513 +++++++++ deps/c-ares/ares_getnameinfo.c | 413 +++++++ deps/c-ares/ares_getopt.c | 123 ++ deps/c-ares/ares_getopt.h | 53 + deps/c-ares/ares_getsock.c | 73 ++ deps/c-ares/ares_init.c | 1627 +++++++++++++++++++++++++++ deps/c-ares/ares_ipv6.h | 75 ++ deps/c-ares/ares_library_init.c | 133 +++ deps/c-ares/ares_library_init.h | 40 + deps/c-ares/ares_llist.c | 87 ++ deps/c-ares/ares_llist.h | 43 + deps/c-ares/ares_mkquery.c | 196 ++++ deps/c-ares/ares_nowarn.c | 53 + deps/c-ares/ares_nowarn.h | 23 + deps/c-ares/ares_options.c | 128 +++ deps/c-ares/ares_parse_a_reply.c | 257 +++++ deps/c-ares/ares_parse_aaaa_reply.c | 257 +++++ deps/c-ares/ares_parse_ns_reply.c | 182 +++ deps/c-ares/ares_parse_ptr_reply.c | 209 ++++ deps/c-ares/ares_parse_srv_reply.c | 180 +++ deps/c-ares/ares_parse_txt_reply.c | 202 ++++ deps/c-ares/ares_private.h | 345 ++++++ deps/c-ares/ares_process.c | 1262 +++++++++++++++++++++ deps/c-ares/ares_query.c | 184 +++ deps/c-ares/ares_rules.h | 145 +++ deps/c-ares/ares_search.c | 323 ++++++ deps/c-ares/ares_send.c | 135 +++ deps/c-ares/ares_strcasecmp.c | 67 ++ deps/c-ares/ares_strcasecmp.h | 31 + deps/c-ares/ares_strdup.c | 43 + deps/c-ares/ares_strdup.h | 27 + deps/c-ares/ares_strerror.c | 57 + deps/c-ares/ares_timeout.c | 81 ++ deps/c-ares/ares_version.c | 12 + deps/c-ares/ares_version.h | 22 + deps/c-ares/ares_writev.c | 80 ++ deps/c-ares/ares_writev.h | 37 + deps/c-ares/bitncmp.c | 60 + deps/c-ares/bitncmp.h | 27 + deps/c-ares/get_ver.awk | 36 + deps/c-ares/inet_net_pton.c | 447 ++++++++ deps/c-ares/inet_net_pton.h | 32 + deps/c-ares/inet_ntop.c | 233 ++++ deps/c-ares/inet_ntop.h | 27 + deps/c-ares/linux/ares_build.h | 112 ++ deps/c-ares/linux/ares_config.h | 513 +++++++++ deps/c-ares/linux/ares_setup.h | 198 ++++ deps/c-ares/mac/ares_build.h | 112 ++ deps/c-ares/mac/ares_config.h | 513 +++++++++ deps/c-ares/mac/ares_setup.h | 198 ++++ deps/c-ares/nameser.h | 194 ++++ deps/c-ares/setup_once.h | 444 ++++++++ deps/c-ares/solaris/ares_build.h | 112 ++ deps/c-ares/solaris/ares_config.h | 513 +++++++++ deps/c-ares/solaris/ares_setup.h | 198 ++++ deps/c-ares/windows_port.c | 23 + deps/c-ares/wscript | 31 + wscript | 28 +- 83 files changed, 15448 insertions(+), 4 deletions(-) create mode 100644 deps/c-ares/AUTHORS create mode 100644 deps/c-ares/CHANGES create mode 100644 deps/c-ares/NEWS create mode 100644 deps/c-ares/README create mode 100644 deps/c-ares/README.cares create mode 100644 deps/c-ares/README.msvc create mode 100644 deps/c-ares/README.node create mode 100644 deps/c-ares/RELEASE-NOTES create mode 100644 deps/c-ares/TODO create mode 100644 deps/c-ares/ares.h create mode 100644 deps/c-ares/ares__close_sockets.c create mode 100644 deps/c-ares/ares__get_hostent.c create mode 100644 deps/c-ares/ares__read_line.c create mode 100644 deps/c-ares/ares__timeval.c create mode 100644 deps/c-ares/ares_cancel.c create mode 100644 deps/c-ares/ares_data.c create mode 100644 deps/c-ares/ares_data.h create mode 100644 deps/c-ares/ares_destroy.c create mode 100644 deps/c-ares/ares_dns.h create mode 100644 deps/c-ares/ares_expand_name.c create mode 100644 deps/c-ares/ares_expand_string.c create mode 100644 deps/c-ares/ares_fds.c create mode 100644 deps/c-ares/ares_free_hostent.c create mode 100644 deps/c-ares/ares_free_string.c create mode 100644 deps/c-ares/ares_gethostbyaddr.c create mode 100644 deps/c-ares/ares_gethostbyname.c create mode 100644 deps/c-ares/ares_getnameinfo.c create mode 100644 deps/c-ares/ares_getopt.c create mode 100644 deps/c-ares/ares_getopt.h create mode 100644 deps/c-ares/ares_getsock.c create mode 100644 deps/c-ares/ares_init.c create mode 100644 deps/c-ares/ares_ipv6.h create mode 100644 deps/c-ares/ares_library_init.c create mode 100644 deps/c-ares/ares_library_init.h create mode 100644 deps/c-ares/ares_llist.c create mode 100644 deps/c-ares/ares_llist.h create mode 100644 deps/c-ares/ares_mkquery.c create mode 100644 deps/c-ares/ares_nowarn.c create mode 100644 deps/c-ares/ares_nowarn.h create mode 100644 deps/c-ares/ares_options.c create mode 100644 deps/c-ares/ares_parse_a_reply.c create mode 100644 deps/c-ares/ares_parse_aaaa_reply.c create mode 100644 deps/c-ares/ares_parse_ns_reply.c create mode 100644 deps/c-ares/ares_parse_ptr_reply.c create mode 100644 deps/c-ares/ares_parse_srv_reply.c create mode 100644 deps/c-ares/ares_parse_txt_reply.c create mode 100644 deps/c-ares/ares_private.h create mode 100644 deps/c-ares/ares_process.c create mode 100644 deps/c-ares/ares_query.c create mode 100644 deps/c-ares/ares_rules.h create mode 100644 deps/c-ares/ares_search.c create mode 100644 deps/c-ares/ares_send.c create mode 100644 deps/c-ares/ares_strcasecmp.c create mode 100644 deps/c-ares/ares_strcasecmp.h create mode 100644 deps/c-ares/ares_strdup.c create mode 100644 deps/c-ares/ares_strdup.h create mode 100644 deps/c-ares/ares_strerror.c create mode 100644 deps/c-ares/ares_timeout.c create mode 100644 deps/c-ares/ares_version.c create mode 100644 deps/c-ares/ares_version.h create mode 100644 deps/c-ares/ares_writev.c create mode 100644 deps/c-ares/ares_writev.h create mode 100644 deps/c-ares/bitncmp.c create mode 100644 deps/c-ares/bitncmp.h create mode 100644 deps/c-ares/get_ver.awk create mode 100644 deps/c-ares/inet_net_pton.c create mode 100644 deps/c-ares/inet_net_pton.h create mode 100644 deps/c-ares/inet_ntop.c create mode 100644 deps/c-ares/inet_ntop.h create mode 100644 deps/c-ares/linux/ares_build.h create mode 100644 deps/c-ares/linux/ares_config.h create mode 100644 deps/c-ares/linux/ares_setup.h create mode 100644 deps/c-ares/mac/ares_build.h create mode 100644 deps/c-ares/mac/ares_config.h create mode 100644 deps/c-ares/mac/ares_setup.h create mode 100644 deps/c-ares/nameser.h create mode 100644 deps/c-ares/setup_once.h create mode 100644 deps/c-ares/solaris/ares_build.h create mode 100644 deps/c-ares/solaris/ares_config.h create mode 100644 deps/c-ares/solaris/ares_setup.h create mode 100644 deps/c-ares/windows_port.c create mode 100644 deps/c-ares/wscript diff --git a/deps/c-ares/AUTHORS b/deps/c-ares/AUTHORS new file mode 100644 index 00000000000..e197a7419d0 --- /dev/null +++ b/deps/c-ares/AUTHORS @@ -0,0 +1,37 @@ +c-ares is based on ares, and these are the people that have worked on it since +the fork was made: + +Alexander Lazic +Alexey Simak +Andreas Rieke +Ashish Sharma +Brad House +Brad Spencer +Bram Matthys +Dan Fandrich +Daniel Stenberg +Dirk Manske +Dominick Meglio +Doug Goldstein +Duncan Wilcox +Eino Tuominen +Erik Kline +George Neill +Gisle Vanem +Guilherme Balena Versiani +Gunter Knauf +Henrik Stoerner +James Bursa +Michael Wallner +Nick Mathewson +Phil Blundell +Ravi Pratap +Robin Cornelius +Sebastian at basti79.de +Shmulik Regev +Steinar H. Gunderson +Tofu Linden +Vlad Dinulescu +William Ahern +Yang Tse +liren at vivisimo.com diff --git a/deps/c-ares/CHANGES b/deps/c-ares/CHANGES new file mode 100644 index 00000000000..b6c608da248 --- /dev/null +++ b/deps/c-ares/CHANGES @@ -0,0 +1,1156 @@ + Changelog for the c-ares project + +Version 1.7.1 (Mar 23, 2010) + +* March 23, 2010 (Daniel Stenberg) +- We switched from CVS to git. See http://github.com/bagder/c-ares + +* March 5, 2010 (Daniel Stenberg) +- Daniel Johnson provided fixes for building with the clang compiler. + +* March 5, 2010 (Yang Tse) +- Added IPv6 name servers support. Implementation has been based on code, + comments and feedback provided November and December of 2008 by Daniel + Stenberg, Gregor Jasny, Phil Blundell and myself, December 2009 by Cedric + Bail, and February 2010 by Jakub Hrozek on the c-ares mailing list. On + March I reviewed all that, selected the best of each, and adjusted or + extended parts of it to make the best fit. + + The external and visible result of all this is that two new functions are + added to the external API, ares_get_servers() and ares_set_servers(), which + becomes now the preferred way of getting and setting name servers for any + ares channel as these support both IPv4 and IPv6 name servers. + + In order to not break ABI compatibility, ares_init_options() with option + mask ARES_OPT_SERVERS and ares_save_options() may still be used in code + which is intended to run on IPv4-only stacks. But remember that these + functions do not support IPv6 name servers. This implies that if the user + is capable of defining or providing an IPv6 name server, and the app is + using ares_init_options() or ares_save_options() at some point to handle + the name servers, the app will likely loose IPv6 name servers. + +* January 28, 2010 (Daniel Stenberg) +- Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't + check for broken connections like ares_process() did. Based on that, I + merged the two functions into a single generic one with two front-ends. + +* December 29, 2009 (Yang Tse) +- Laszlo Tamas Szabo adjusted Makefile.msvc compiler options so that where + run-time error checks enabling compiler option /GZ was used it is replaced + with equivalent /RTCsu for Visual Studio 2003 and newer versions. Option + /GX is replaced with equivalent /EHsc for all versions. Also fixed socket + data type for internal configure_socket function. + +* December 21, 2009 (Yang Tse) +- Ingmar Runge noticed that Windows config-win32.h configuration file + did not include a definition for HAVE_CLOSESOCKET which resulted in + function close() being inappropriately used to close sockets. + +Version 1.7.0 (Nov 30, 2009) + +* November 26, 2009 (Yang Tse) +- Larry Lansing fixed ares_parse_srv_reply to properly parse replies + which might contain non-SRV answers, skipping over potential non-SRV + ones such as CNAMEs. + +* November 23, 2009 (Yang Tse) +- Changed naming convention for c-ares libraries built with MSVC, details + and build instructions provided in README.msvc file. + +* November 22, 2009 (Yang Tse) +- Jakub Hrozek fixed more function prototypes in man pages to sync them + with the ones declared in ares.h + +- Jakub Hrozek renamed addrttl and addr6ttl structs to ares_addrttl and + ares_addr6ttl in order to prevent name space pollution, along with + necessary changes to code base and man pages.This change does not break + ABI, there is no need to recompile existing applications. But existing + applications using these structs with the old name will need source code + adjustments when recompiled using c-ares 1.7.0. + +* November 21, 2009 (Yang Tse) +- Added manifest stuff to Makefile.msvc. + +* November 20, 2009 (Yang Tse) +- Fixed several function prototypes in man pages that were out of sync + with the ones declared in ares.h. Added ares_free_data() along with + man page. Updated ares_parse_srv_reply() and ares_parse_txt_reply() + with changes from Jakub Hrozek making these now return linked lists + instead of arrays, and merging the ares_free_data() adjustments. + +* November 10, 2009 (Yang Tse) +- Updated MSVC 6.0 project files to match settings from Makefile.msvc. + +* November 9, 2009 (Yang Tse) +- Makefile.msvc is now the reference method to build c-ares and sample + programs with any MSVC compiler or MS Visual Studio version. If no + option or target are specified it builds dynamic and static c-ares + libraries in debug and release flavours and also builds all sample + programs using each of the different c-ares libraries. + +* November 2, 2009 (Yang Tse) +- Renamed c-ares setup.h to ares_setup.h + +* October 31, 2009 (Yang Tse) +- Symbol hiding configure options are named now --enable-symbol-hiding + and --disable-symbol-hiding in an attempt to make them less ambiguous. + +* October 30, 2009 (Yang Tse) +- Many fixes for ares_parse_txt_reply() + +* October 29, 2009 (Daniel Stenberg) +- Jakub Hrozek added ares_parse_txt_reply() for TXT parsing + +* October 29, 2009 (Yang Tse) +- Updated MSVC 6.0 workspace and project files that allows building + dynamic and static c-ares libraries in debug and release flavours. + Additionally each of the three sample programs is built against + each of the four possible c-ares libraries, generating all this + a total number of 12 executables and 4 libraries. + +* October 28, 2009 (Yang Tse) +- Initial step towards the ability to reduce c-ares exported symbols + when built as a shared library based on the 'visibility' attribute + for GNUC and Intel compilers and based on __global for Sun compilers, + taking also in account __declspec function decoration for Win32 and + Symbian DLL's. + +* October 27, 2009 (Yang Tse) +- Fixed Pelles C Win32 target compilation issues. + +* October 23, 2009 (Yang Tse) +- John Engelhart noticed an unreleased problem relative to a duplicate + ARES_ECANCELLED error code value and missing error code description. + +* October 7, 2009 (Yang Tse) +- Overhauled ares__get_hostent() Fixing out of bounds memory overwrite + triggered with malformed /etc/hosts file. Improving parsing of /etc/hosts + file. Validating requested address family. Ensuring that failures always + return a NULL pointer. Adjusting header inclusions. + +* October 6, 2009 (Yang Tse) +- Fix ssize_t redefinition errors on WIN64 reported by Alexey Simak. + +* September 29, 2009 (Yang Tse) +- Make configure script also check if _REENTRANT definition is required to + make errno available as a preprocessor macro. + +* September 7, 2009 (Yang Tse) +- Add T_SRV portability check to ares_parse_srv_reply.c + +* 4 Sep 2009 (Daniel Stenberg) +- Jakub Hrozek added ares_parse_srv_reply() for SRV parsing + +* 3 Aug 2009 (Daniel Stenberg) +- Joshua Kwan fixed the init routine to fill in the defaults for stuff that + fails to get inited by other means. This fixes a case of when the c-ares + init fails when internet access is fone. + +- Timo Teras changed the reason code used in the resolve callback done when + ares_cancel() is used, to be ARES_ECANCELLED instead of ARES_ETIMEOUT to + better allow the callback to know what's happening. + +* 14 Jul 2009 (Guenter Knauf) +- renamed generated config.h to ares_config.h to avoid any future clashes + with config.h from other projects. + +* June 20 2009 (Yang Tse) +- Refactor how libraries are checked for connect() function in configure + script and check for connect() as it is done for other functions. + +* June 19 2009 (Yang Tse) +- Make sclose() function-like macro definition used to close a socket, + now solely based on HAVE_CLOSESOCKET and HAVE_CLOSESOCKET_CAMEL + config file preprocessor definitions + +* June 18 2009 (Yang Tse) +- Add CloseSocket camel case function check for configure script. + +* June 17 2009 (Yang Tse) +- Check for socket() and closesocket() as it is done for other functions + in configure script. + +* June 11 2009 (Yang Tse) +- Modified buildconf so that when automake runs it copies missing files + instead of symlinking them. + +* June 8 2009 (Yang Tse) +- Removed buildconf.bat from release and daily snapshot archives. This + file is only for CVS tree checkout builds. + +* May 26 2009 (Yang Tse) +- Added --enable-curldebug configure option to enable and disable building + with the low-level curl debug memory tracking 'feature' to allow decoupled + setting from --enable-debug, allowing again to build c-ares independently + out of the CVS tree. + + For the c-ares library option --enable-debug enables debug build features + which are _not_ related with memory tracking. For the c-ares library when + --enable-debug is given it does not enable the memory tracking feature. If + you wish to enable the curl debug memory tracking you must use configure + option --enable-curldebug explicitily to do so. + + Internally, definition of preprocessor symbol DEBUGBUILD restricts code + which is only compiled for debug enabled builds. And symbol CURLDEBUG is + used to differentiate code which is _only_ used for memory tracking. + + Make ares_init(), ares_dup() and ares_init_options() fail returning + ARES_ENOTINITIALIZED if library initialization has not been performed + calling ares_library_init(). + +* May 20 2009 (Yang Tse) +- Added ares_library_init() and ares_library_cleanup() man pages. + +* May 19 2009 (Yang Tse) +- Introduced ares_library_init() and ares_library_cleanup() functions. + + This is an API and ABI break for Win32/64 systems. Non-Win32/64 build targets + using c-ares 1.7.0 can still survive without calling these functions. Read all + the details on ares_library_init(3) and ares_library_cleanup(3) man pages that + are included. + + curl/libcurl 7.19.5 is fully compatible with c-ares 1.7.0 on all systems. + + In order to use c-ares 1.7.0 with curl/libcurl on Win32/64 systems it is + required that curl/libcurl is 7.19.5 or newer. In other words, it is not + possible on Win32/64 to use c-ares 1.7.0 with a curl/libcurl version less + than 7.19.5 + +* May 11 2009 (Daniel Stenberg) +- Gregor Jasny made c-ares link with libtool 's -export-symbols-regex option to + only expose functions starting with ares_. + +* May 7 2009 (Yang Tse) +- Fix an m4 overquoting triggering a spurious 'AS_TR_CPP' symbol definition + attempt in generated config.h + +* May 2 2009 (Yang Tse) +- Use a build-time configured ares_socklen_t data type instead of socklen_t. + +* April 21 2009 (Yang Tse) +- Moved potential inclusion of system's malloc.h and memory.h header files to + setup_once.h. Inclusion of each header file is based on the definition of + NEED_MALLOC_H and NEED_MEMORY_H respectively. + +* March 11 2009 (Yang Tse) +- Japheth Cleaver fixed acountry.c replacing u_long with unsigned long. + +* February 20 2009 (Yang Tse) +- Do not halt compilation when using VS2008 to build a Windows 2000 target. + +* February 3 2009 (Phil Blundell) +- If the server returns garbage or nothing at all in response to an AAAA query, + go on and ask for A records anyway. + +* January 31 2009 (Daniel Stenberg) +- ares_gethostbyname() now accepts 'AF_UNSPEC' as a family for resolving + either AF_INET6 or AF_INET. It works by accepting any of the looksups in the + hosts file, and it resolves the AAAA field with a fallback to A. + +* January 14 2009 (Daniel Stenberg) +- ares.h no longer uses the HAVE_STRUCT_IN6_ADDR define check, but instead it + now declares the private struct ares_in6_addr for all systems instead of + relying on one possibly not present in the system. + +* January 13 2009 (Phil Blundell) +- ares__send_query() now varies the retry timeout pseudo-randomly to avoid + packet storms when several queries were started at the same time. + +* January 11 2009 (Daniel Stenberg) +- Phil Blundell added the internal function ares__expand_name_for_response() + that is now used by the ares_parse_*_reply() functions instead of the + ares_expand_name() simply to easier return ARES_EBADRESP for the cases where + the name expansion fails as in responses that really isn't expected. + +Version 1.6.0 (Dec 9, 2008) + +* December 9 2008 (Gisle Vanem) + + Fixes for Win32 targets using the Watt-32 tcp/ip stack. + +* Dec 4 2008 (Daniel Stenberg) + + Gregor Jasny provided the patch that introduces ares_set_socket_callback(), + and I edited it to also get duped by ares_dup(). + +* Dec 3 2008 (Daniel Stenberg) + + API changes: + + I made sure the public ares_config struct looks like before and yet it + supports the ROTATE option thanks to c-ares now storing the "optmask" + internally. Thus we should be ABI compatible with the past release(s) + now. My efforts mentioned below should not break backwards ABI compliance. + + Here's how I suggest we proceed with the API: + + ares_init() will be primary "channel creator" function. + + ares_init_options() will continue to work exactly like now and before. For + starters, it will be the (only) way to set the existing options. + + ares_save_options() will continue to work like today, but will ONLY save + options that you can set today (including ARES_OPT_ROTATE actually) but new + options that we add may not be saved with this. + + Instead we introduce: + + ares_dup() that instead can make a new channel and clone the config used + from an existing channel. It will then clone all config options, including + future new things we add. + + ares_set_*() style functions that set (new) config options. As a start we + simply add these for new functionality, but over time we can also introduce + them for existing "struct ares_options" so that we can eventually deprecate + the two ares_*_options() functions. + + ares_get_*() style functions for extracting info from a channel handle that + should be used instead of ares_save_options(). + +* Nov 26 2008 (Yang Tse) +- Brad Spencer provided changes to allow buildconf to work on OS X. + +- Gerald Combs fixed a bug in ares_parse_ptr_reply() which would cause a + buffer to shrink instead of expand if a reply contained 8 or more records. + +* Nov 25 2008 (Yang Tse) +- In preparation for the upcomming IPv6 nameservers patch, the internal + ares_addr union is now changed into an internal struct which also holds + the address family. + +* Nov 19 2008 (Daniel Stenberg) +- Brad Spencer brought the new function ares_gethostbyname_file() which simply + resolves a host name from the given file, using the regular hosts syntax. + +* Nov 1 2008 (Daniel Stenberg) +- Carlo Contavalli added support for the glibc "rotate" option, as documented + in man resolv.conf: + + causes round robin selection of nameservers from among those listed. This + has the effect of spreading the query load among all listed servers, rather + than having all clients try the first listed server first every time. + + You can enable it with ARES_OPT_ROTATE + +* Oct 21 2008 (Yang Tse) + Charles Hardin added handling of EINPROGRESS for UDP connects. + +* Oct 18 2008 (Daniel Stenberg) + Charles Hardin made adig support a regular numerical dotted IP address for the + -s option as well. + +* Oct 7 2008 (Yang Tse) +- Added --enable-optimize configure option to enable and disable compiler + optimizations to allow decoupled setting from --enable-debug. + +* Oct 2 2008 (Yang Tse) +- Added --enable-warnings configure option to enable and disable strict + compiler warnings to allow decoupled setting from --enable-debug. + +* Sep 17 2008 (Yang Tse) +- Code reorganization to allow internal/private use of "nameser.h" to any + system that lacks arpa/nameser.h or arpa/nameser_compat.h header files. + +* Sep 16 2008 (Yang Tse) +- Code reorganization to allow internal/private use of ares_writev to any + system that lacks the writev function. + +* Sep 15 2008 (Yang Tse) +- Code reorganization to allow internal/private use of ares_strcasecmp to any + system that lacks the strcasecmp function. + +- Improve configure detection of some string functions. + +* Sep 11 2008 (Yang Tse) +- Code reorganization to allow internal/private use of ares_strdup to any + system that lacks the strdup function. + +Version 1.5.3 (Aug 29, 2008) + +* Aug 25 2008 (Yang Tse) +- Improvement by Brad House: + + This patch addresses an issue in which a response could be sent back to the + source port of a client from a different address than the request was made to. + This is one form of a DNS cache poisoning attack. + + The patch simply uses recvfrom() rather than recv() and validates that the + address returned from recvfrom() matches the address of the server we have + connected to. Only necessary on UDP sockets as they are connection-less, TCP + is unaffected. + +- Fix by George Neill: + Fixed compilation of acountry sample application failure on some systems. + +* Aug 4 2008 (Daniel Stenberg) +- Fix by Tofu Linden: + + The symptom: + * Users (usually, but not always) on 2-Wire routers and the Comcast service + and a wired connection to their router would find that the second and + subsequent DNS lookups from fresh processes using c-ares to resolve the same + address would cause the process to never see a reply (it keeps polling for + around 1m15s before giving up). + + The repro: + * On such a machine (and yeah, it took us a lot of QA to find the systems + that reproduce such a specific problem!), do 'ahost www.secondlife.com', + then do it again. The first process's lookup will work, subsequent lookups + will time-out and fail. + + The cause: + * init_id_key() was calling randomize_key() *before* it initialized + key->state, meaning that the randomness generated by randomize_key() is + immediately overwritten with deterministic values. (/dev/urandom was also + being read incorrectly in the c-ares version we were using, but this was + fixed in a later version.) + * This makes the stream of generated query-IDs from any new c-ares process + be an identical and predictable sequence of IDs. + * This makes the 2-Wire's default built-in DNS server detect these queries + as probable-duplicates and (erroneously) not respond at all. + + +* Aug 4 2008 (Yang Tse) +- Autoconf 2.62 has changed the behaviour of the AC_AIX macro which we use. + Prior versions of autoconf defined _ALL_SOURCE if _AIX was defined. 2.62 + version of AC_AIX defines _ALL_SOURCE and other four preprocessor symbols + no matter if the system is AIX or not. To keep the traditional behaviour, + and an uniform one across autoconf versions AC_AIX is replaced with our + own internal macro CARES_CHECK_AIX_ALL_SOURCE. + +* Aug 1 2008 (Yang Tse) +- Configure process now checks if the preprocessor _REENTRANT symbol is already + defined. If it isn't currently defined a set of checks are performed to test + if its definition is required to make visible to the compiler a set of *_r + functions. Finally, if _REENTRANT is already defined or needed it takes care + of making adjustments necessary to ensure that it is defined equally for the + configure process tests and generated config file. + +* Jul 20 2008 (Yang Tse) +- When recvfrom prototype uses a void pointer for arguments 2, 5 or 6 this will + now cause the definition, as appropriate, of RECVFROM_TYPE_ARG2_IS_VOID, + RECVFROM_TYPE_ARG5_IS_VOID or RECVFROM_TYPE_ARG6_IS_VOID. + +* Jul 17 2008 (Yang Tse) +- RECVFROM_TYPE_ARG2, RECVFROM_TYPE_ARG5 and RECVFROM_TYPE_ARG6 are now defined + to the data type pointed by its respective argument and not the pointer type. + +* Jul 16 2008 (Yang Tse) +- Improved configure detection of number of arguments for getservbyport_r. + Detection is now based on compilation checks instead of linker ones. + +- Configure process now checks availability of recvfrom() socket function and + finds out its return type and the types of its arguments. Added definitions + for non-configure systems config files, and introduced macro sreadfrom which + will be used on udp sockets as a recvfrom() wrapper in the future. + +* Jul 15 2008 (Yang Tse) +- Introduce definition of _REENTRANT symbol in setup.h to improve library + usability. Previously the configure process only used the AC_SYS_LARGEFILE + macro for debug builds, now it is also used for non-debug ones enabling the + use of configure options --enable-largefile and --disable-largefile which + might be needed for library compatibility. Remove checking the size of + curl_off_t, it is no longer needed. + +* Jul 3 2008 (Daniel Stenberg) +- Phil Blundell: If you ask ares_gethostbyname() to do an AF_INET6 lookup and + the target host has only A records, it automatically falls back to an + AF_INET lookup and gives you the A results. However, if the target host has + a CNAME record, this behaviour is defeated since the original query does + return some data even though ares_parse_aaa_reply() doesn't consider it + relevant. Here's a small patch to make it behave the same with and without + the CNAME. + +* Jul 2 2008 (Yang Tse) +- Fallback to gettimeofday when monotonic clock is unavailable at run-time. + +* Jun 30 2008 (Daniel Stenberg) + +- As was pointed out to me by Andreas Schuldei, the MAXHOSTNAMELEN define is + not posix or anything and thus c-ares failed to build on hurd (and possibly + elsewhere). The define was also somewhat artificially used in the windows + port. Now, I instead rewrote the use of gethostbyname to enlarge the host + name buffer in case of need and totally avoid the use of the MAXHOSTNAMELEN + define. I thus also removed the defien from the namser.h file where it was + once added for the windows build. + + I also fixed init_by_defaults() function to not leak memory in case if + error. + +* Jun 9 2008 (Yang Tse) + +- Make libcares.pc generated file for pkg-config include information relative + to the libraries needed for the static linking of c-ares. + +* May 30 2008 (Yang Tse) + +- Brad House fixed a missing header file inclusion in adig sample program. + +Version 1.5.2 (May 29, 2008) + +* May 13 2008 (Daniel Stenberg) + +- Introducing millisecond resolution support for the timeout option. See + ares_init_options()'s ARES_OPT_TIMEOUTMS. + +* May 9 2008 (Yang Tse) + +- Use monotonic time source if available, for private function ares__tvnow() + +* May 7 2008 (Daniel Stenberg) + +- Sebastian made c-ares able to return all PTR-records when doing reverse + lookups. It is not common practice to have multiple PTR-Records for a single + IP, but its perfectly legal and some sites have those. + +- Doug Goldstein provided a configure patch: updates autoconf 2.13 usage to + autoconf 2.57 usage (which is the version you have specified as the minimum + version). It's a minor change but it does clean up some warnings with newer + autoconf (specifically 2.62). + +* May 5 2008 (Yang Tse) + +- Improved parsing of resolver configuration files. + +* April 4 2008 (Daniel Stenberg) + +- Eino Tuominen improved the code when a file is used to seed the randomizer. + +- Alexey Simak made adig support NAPTR records + +- Alexey Simak fixed the VC dsp file by adding the missing source file + ares_expand_string.c + +* December 11 2007 (Gisle Vanem) + +- Added another sample application; acountry.c which converts an + IPv4-address(es) and/or host-name(s) to country-name and country-code. + This uses the service of the DNSBL at countries.nerd.dk. + +* December 3 2007 (Daniel Stenberg) + +- Brad Spencer fixed the configure script to assume that there's no + /dev/urandom when built cross-compiled as then the script cannot check for + it. + +- Erik Kline cleaned up ares_gethostbyaddr.c:next_lookup() somewhat + +Version 1.5.1 (Nov 21, 2007) + +* November 21 2007 (Daniel Stenberg) + +- Robin Cornelius pointed out that ares_llist.h was missing in the release + archive for 1.5.0 + +Version 1.5.0 (Nov 21, 2007) + +* October 2 2007 (Daniel Stenberg) + +- ares_strerror() segfaulted if the input error number was out of the currently + supported range. + +- Yang Tse: Avoid a segfault when generating a DNS "Transaction ID" in + internal function init_id_key() under low memory conditions. + +* September 28 2007 (Daniel Stenberg) + +- Bumped version to 1.5.0 for next release and soname bumped to 2 due to ABI + and API changes in the progress callback (and possibly more coming up from + Steinar) + +* September 28 2007 (Steinar H. Gunderson) + +- Don't skip a server if it's the only one. (Bugfix from the Google tree.) + +- Made the query callbacks receive the number of timeouts that happened during + the execution of a query, and updated documentation accordingly. (Patch from + the Google tree.) + +- Support a few more socket options: ARES_OPT_SOCK_SNDBUF and + ARES_OPT_SOCK_RCVBUF + +- Always register for TCP events even if there are no outstanding queries, as + the other side could always close the connection, which is a valid event + which should be responded to. + +* September 22 2007 (Daniel Stenberg) + +- Steinar H. Gunderson fixed: Correctly clear sockets from the fd_set on in + several functions (write_tcp_data, read_tcp_data, read_udp_packets) so that + if it fails and the socket is closed the following code doesn't try to use + the file descriptor. + +- Steinar H. Gunderson modified c-ares to now also do to DNS retries even when + TCP is used since there are several edge cases where it still makes sense. + +- Brad House provided a fix for ares_save_options(): + + Apparently I overlooked something with the ares_save_options() where it + would try to do a malloc(0) when no options of that type needed to be saved. + On most platforms, this was fine because malloc(0) doesn't actually return + NULL, but on AIX it does, so ares_save_options would return ARES_ENOMEM. + +* July 14 2007 (Daniel Stenberg) + +- Vlad Dinulescu fixed two outstanding valgrind reports: + + 1. In ares_query.c , in find_query_by_id we compare q->qid (which is a short + int variable) with qid, which is declared as an int variable. Moreover, + DNS_HEADER_SET_QID is used to set the value of qid, but DNS_HEADER_SET_QID + sets only the first two bytes of qid. I think that qid should be declared as + "unsigned short" in this function. + + 2. The same problem occurs in ares_process.c, process_answer() . query->qid + (an unsigned short integer variable) is compared with id, which is an + integer variable. Moreover, id is initialized from DNS_HEADER_QID which sets + only the first two bytes of id. I think that the id variable should be + declared as "unsigned short" in this function. + + Even after declaring these variables as "unsigned short", the valgrind + errors are still there. Which brings us to the third problem. + + 3. The third problem is that Valgrind assumes that query->qid is not + initialised correctly. And it does that because query->qid is set from + DNS_HEADER_QID(qbuf); Valgrind says that qbuf has unitialised bytes. And + qbuf has uninitialised bytes because of channel->next_id . And next_id is + set by ares_init.c:ares__generate_new_id() . I found that putting short r=0 + in this function (instead of short r) makes all Valgrind warnings go away. + I have studied ares__rc4() too, and this is the offending line: + + buffer_ptr[counter] ^= state[xorIndex]; (ares_query.c:62) + + This is what triggers Valgrind.. buffer_ptr is unitialised in this function, + and by applying ^= on it, it remains unitialised. + +Version 1.4.0 (June 8, 2007) + +* June 4 2007 (Daniel Stenberg) + +- James Bursa reported a major memory problem when resolving multi-IP names + and I found and fixed the problem. It was added by Ashish Sharma's patch + two days ago. + + When I then tried to verify multiple entries in /etc/hosts after my fix, I + got another segfault and decided this code was not ripe for inclusion and I + reverted the patch. + +* June 2 2007 + +- Brad Spencer found and fixed three flaws in the code, found with the new + gcc 4.2.0 warning: -Waddress + +- Brad House fixed VS2005 compiler warnings due to time_t being 64bit. + He also made recent Microsoft compilers use _strdup() instead of strdup(). + +- Brad House's man pages for ares_save_options() and ares_destroy_options() + were added. + +- Ashish Sharma provided a patch for supporting multiple entries in the + /etc/hosts file. Patch edited for coding style and functionality by me + (Daniel). + +* May 30 2007 + +- Shmulik Regev brought cryptographically secure transaction IDs: + + The c-ares library implementation uses a DNS "Transaction ID" field that is + seeded with a pseudo random number (based on gettimeofday) which is + incremented (++) between consecutive calls and is therefore rather + predictable. In general, predictability of DNS Transaction ID is a well + known security problem (e.g. + http://bak.spc.org/dms/archive/dns_id_attack.txt) and makes a c-ares based + implementation vulnerable to DNS poisoning. Credit goes to Amit Klein + (Trusteer) for identifying this problem. + + The patch I wrote changes the implementation to use a more secure way of + generating unique IDs. It starts by obtaining a key with reasonable entropy + which is used with an RC4 stream to generate the cryptographically secure + transaction IDs. + + Note that the key generation code (in ares_init:randomize_key) has two + versions, the Windows specific one uses a cryptographically safe function + provided (but undocumented :) by the operating system (described at + http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx). The + default implementation is a bit naive and uses the standard 'rand' + function. Surely a better way to generate random keys exists for other + platforms. + + The patch can be tested by using the adig utility and using the '-s' option. + +- Brad House added ares_save_options() and ares_destroy_options() that can be + used to keep options for later re-usal when ares_init_options() is used. + + Problem: Calling ares_init() for each lookup can be unnecessarily resource + intensive. On windows, it must LoadLibrary() or search the registry + on each call to ares_init(). On unix, it must read and parse + multiple files to obtain the necessary configuration information. In + a single-threaded environment, it would make sense to only + ares_init() once, but in a heavily multi-threaded environment, it is + undesirable to ares_init() and ares_destroy() for each thread created + and track that. + + Solution: Create ares_save_options() and ares_destroy_options() functions to + retrieve and free options obtained from an initialized channel. The + options populated can be used to pass back into ares_init_options(), + it should populate all needed fields and not retrieve any information + from the system. Probably wise to destroy the cache every minute or + so to prevent the data from becoming stale. + +- Daniel S added ares_process_fd() to allow applications to ask for processing + on specific sockets and thus avoiding select() and associated + functions/macros. This function will be used by upcoming libcurl releases + for this very reason. It also made me export the ares_socket_t type in the + public ares.h header file, since ares_process_fd() uses that type for two of + the arguments. + +* May 25 2007 + +- Ravi Pratap fixed a flaw in the init_by_resolv_conf() function for windows + that could cause it to return a bad return code. + +* April 16 2007 + +- Yang Tse: Provide ares_getopt() command-line parser function as a source + code helper function, not belonging to the actual c-ares library. + +* February 19 2007 + +- Vlad Dinulescu added ares_parse_ns_reply(). + +* February 13 2007 + +- Yang Tse: Fix failure to get the search sequence of /etc/hosts and + DNS from /etc/nsswitch.conf, /etc/host.conf or /etc/svc.conf when + /etc/resolv.conf did not exist or was unable to read it. + +* November 22 2006 + +- Install ares_dns.h too + +- Michael Wallner fixed this problem: When I set domains in the options + struct, and there are domain/search entries in /etc/resolv.conf, the domains + of the options struct will be overridden. + +* November 6 2006 + +- Yang Tse removed a couple of potential zero size memory allocations. + +- Andreas Rieke fixed the line endings in the areslib.dsp file that I (Daniel) + broke in the 1.3.2 release. We should switch to a system where that file is + auto-generated. We could rip some code for that from curl... + +Version 1.3.2 (November 3, 2006) + +* October 12 2006 + +- Prevent ares_getsock() to overflow if more than 16 sockets are used. + +* September 11 2006 + +- Guilherme Balena Versiani: I noted a strange BUG in Win32 port + (ares_init.c/get_iphlpapi_dns_info() function): when I disable the network + by hand or disconnect the network cable in Windows 2000 or Windows XP, my + application gets 127.0.0.1 as the only name server. The problem comes from + 'GetNetworkParams' function, that returns the empty string "" as the only + name server in that case. Moreover, the Windows implementation of + inet_addr() returns INADDR_LOOPBACK instead of INADDR_NONE. + +* August 29 2006 + +- Brad Spencer did + + o made ares_version.h use extern "C" for c++ compilers + o fixed compiler warnings in ares_getnameinfo.c + o fixed a buffer position init for TCP reads + +* August 3 2006 + +- Ravi Pratap fixed ares_getsock() to actually return the proper bitmap and + not always zero! + +Version 1.3.1 (June 24, 2006) + +* July 23, 2006 + +- Gisle Vanem added getopt() to the ahost program. Currently accepts + only [-t {a|aaaa}] to specify address family in ares_gethostbyname(). + +* June 19, 2006 + +- (wahern) Removed "big endian" DNS section and RR data integer parser + macros from ares_dns.h, which break c-ares on my Sparc64. Bit-wise + operations in C operate on logical values. And in any event the octets are + already in big-endian (aka network) byte order so they're being reversed + (thus the source of the breakage). + +* June 18, 2006 + +- William Ahern handles EAGAIN/EWOULDBLOCK errors in most of the I/O calls + from area_process.c. + + TODO: Handle one last EAGAIN for a UDP socket send(2) in + ares__send_query(). + +* May 10, 2006 + +- Bram Matthys brought my attention to a libtool peculiarity where detecting + things such as C++ compiler actually is a bad thing and since we don't need + that detection I added a work-around, much inspired by a previous patch by + Paolo Bonzini. This also shortens the configure script quite a lot. + +* May 3, 2006 + +- Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes + c-ares call a callback on socket state changes. A better way than the + ares_getsock() to get full control over the socket state. + +* January 9, 2006 + +- Alexander Lazic improved the getservbyport_r() configure check. + +* January 6, 2006 + +- Alexander Lazic pointed out that the buildconf should use the ACLOCAL_FLAGS + variable for easier controlling what it does and how it runs. + +* January 5, 2006 + +- James Bursa fixed c-ares to find the hosts file on RISC OS, and made it + build with newer gcc versions that no longer defines "riscos". + +* December 22 + +- Daniel Stenberg added ares_getsock() that extracts the set of sockets to + wait for action on. Similar to ares_fds() but not restricted to using + select() for the waiting. + +* November 25 + +- Yang Tse fixed some send() / recv() compiler warnings + +* September 18 + +- Added constants that will be used by ares_getaddrinfo + +- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it + is available to ensure it works properly in a threaded environment. + +* September 10 + +- configure fix for detecting a member in the sockaddr_in6 struct which failed + on ipv6-enabled HP-UX 11.00 + +Version 1.3.0 (August 29, 2005) + +* August 21 + +- Alfredo Tupone provided a fix for the Windows code in get_iphlpapi_dns_info() + when getting the DNS server etc. + +* June 19 + +- Added some checks for the addrinfo structure. + +* June 2 + +- William Ahern: + + Make UDP sockets non-blocking. I've confirmed that at least on Linux 2.4 a + read event can come back from poll() on a valid SOCK_DGRAM socket but + recv(2) will still block. This patch doesn't ignore EAGAIN in + read_udp_packets(), though maybe it should. (This patch was edited by Daniel + Stenberg and a new configure test was added (imported from curl's configure) + to properly detect what non-blocking socket approach to use.) + + I'm not quite sure how this was happening, but I've been seeing PTR queries + which seem to return empty responses. At least, they were empty when calling + ares_expand_name() on the record. Here's a patch which guarantees to + NUL-terminate the expanded name. The old behavior failed to NUL-terminate if + len was 0, and this was causing strlen() to run past the end of the buffer + after calling ares_expand_name() and getting ARES_SUCCESS as the return + value. If q is not greater than *s then it's equal and *s is always + allocated with at least one byte. + +* May 16 + +- Added ares_getnameinfo which mimics the getnameinfo API (another feature + that could use testing). + +* May 14 + +- Added an inet_ntop function from BIND for systems that do not have it. + +* April 9 + +- Made sortlist support IPv6 (this can probably use some testing). + +- Made sortlist support CIDR matching for IPv4. + +* April 8 + +- Added preliminary IPv6 support to ares_gethostbyname. Currently, sortlist + does not work with IPv6. Also provided an implementation of bitncmp from + BIND for systems that do not supply this function. This will be used to add + IPv6 support to sortlist. + +- Made ares_gethostbyaddr support IPv6 by specifying AF_INET6 as the family. + The function can lookup IPv6 addresses both from files (/etc/hosts) and + DNS lookups. + +* April 7 + +- Tupone Alfredo fixed includes of arpa/nameser_compat.h to build fine on Mac + OS X. + +* April 5 + +- Dominick Meglio: Provided implementations of inet_net_pton and inet_pton + from BIND for systems that do not include these functions. + +* March 11, 2005 + +- Dominick Meglio added ares_parse_aaaa_reply.c and did various + adjustments. The first little steps towards IPv6 support! + +* November 7 + +- Fixed the VC project and makefile to use ares_cancel and ares_version + +* October 24 + +- The released ares_version.h from 1.2.1 says 1.2.0 due to a maketgz flaw. + This is now fixed. + +Version 1.2.1 (October 20, 2004) + +* September 29 + +- Henrik Stoerner fix: got a report that Tru64 Unix (the unix from Digital + when they made Alpha's) uses /etc/svc.conf for the purpose fixed below for + other OSes. He made c-ares check for and understand it if present. + +- Now c-ares will use local host name lookup _before_ DNS resolving by default + if nothing else is told. + +* September 26 + +- Henrik Stoerner: found out that c-ares does not look at the /etc/host.conf + file to determine the sequence in which to search /etc/hosts and DNS. So on + systems where this order is defined by /etc/host.conf instead of a "lookup" + entry in /etc/resolv.conf, c-ares will always default to looking in DNS + first, and /etc/hosts second. + + c-ares now looks at + + 1) resolv.conf (for the "lookup" line); + 2) nsswitch.fon (for the "hosts:" line); + 3) host.conf (for the "order" line). + + First match wins. + +- Dominick Meglio patched: C-ares on Windows assumed that the HOSTS file is + located in a static location. It assumed + C:\Windows\System32\Drivers\Etc. This is a poor assumption to make. In fact, + the location of the HOSTS file can be changed via a registry setting. + + There is a key called DatabasePath which specifies the path to the HOSTS + file: + http://www.microsoft.com/technet/itsolutions/network/deploy/depovg/tcpip2k.mspx + + The patch will make c-ares correctly consult the registry for the location + of this file. + +* August 29 + +- Gisle Vanem fixed the MSVC build files. + +* August 20 + +- Gisle Vanem made c-ares build and work with his Watt-32 TCP/IP stack. + +* August 13 + +- Harshal Pradhan made a minor syntax change in ares_init.c to make it build + fine with MSVC 7.1 + +* July 24 + +- Made the lib get built static only if --enable-debug is used. + +- Gisle Vanem fixed: + + Basically in loops like handle_errors(), 'query->next' was assigned a local + variable and then query was referenced after the memory was freed by + next_server(). I've changed that so next_server() and end_query() returns + the next query. So callers should use this ret-value. + + The next problem was that 'server->tcp_buffer_pos' had a random value at + entry to 1st recv() (luckily causing Winsock to return ENOBUFS). + + I've also added a ares_writev() for Windows to streamline the code a bit + more. + +* July 20 +- Fixed a few variable return types for some system calls. Made configure + check for ssize_t to make it possible to use that when receiving the send() + error code. This is necessary to prevent compiler warnings on some systems. + +- Made configure create config.h, and all source files now include setup.h that + might include the proper config.h (or a handicrafted alternative). + +- Switched to 'ares_socket_t' type for sockets in ares, since Windows don't + use 'int' for that. + +- automake-ified and libool-ified c-ares. Now it builds libcares as a shared + lib on most platforms if wanted. (This bloated the size of the release + archive with another 200K!) + +- Makefile.am now uses Makefile.inc for the c sources, h headers and man + pages, to make it easier for other makefiles to use the exact same set of + files. + +- Adjusted 'maketgz' to use the new automake magic when building distribution + archives. + +- Anyone desires HTML and/or PDF versions of the man pages in the release + archives? + +* July 3 +- Gnter Knauf made c-ares build and run on Novell Netware. + +* July 1 +- Gisle Vanem provided Makefile.dj to build with djgpp, added a few more djgpp + fixes and made ares not use 'errno' to provide further info on Windows. + +* June 30 +- Gisle Vanem made it build with djgpp and run fine with the Watt-32 stack. + +* June 10 +- Gisle Vanem's init patch for Windows: + + The init_by_resolv_conf() function fetches the DNS-server(s) + from a series of registry branches. + + This can be wrong in the case where DHCP has assigned nameservers, but the + user has overridden these servers with other prefered settings. Then it's + wrong to use the DHCPNAMESERVER setting in registry. + + In the case of no global DHCP-assigned or fixed servers, but DNS server(s) + per adapter, one has to query the adapter branches. But how can c-ares know + which adapter is valid for use? AFAICS it can't. There could be one adapter + that is down (e.g. a VPN adapter). + + So it's better to leave this to the IP Helper API (iphlapi) available in + Win-98/2000 and later. My patch falls-back to the old way if not available. + +* June 8 +- James Bursa fixed an init issue for RISC OS. + +* May 11 +- Nico Stappenbelt reported that when processing domain and search lines in + the resolv.conf file, the first entry encountered is processed and used as + the search list. According to the manual pages for both Linux, Solaris and + Tru64, the last entry of either a domain or a search field is used. + + This is now adjusted in the code + +Version 1.2.0 (April 13, 2004) + +* April 2, 2004 +- Updated various man pages to look nicer when converted to HTML on the web + site. + +* April 1, 2004 +- Dirk Manske provided a new function that is now named ares_cancel(). It is + used to cancel/cleanup a resolve/request made using ares functions on the + given ares channel. It does not destroy/kill the ares channel itself. + +- Dominick Meglio cleaned up the formatting in several man pages. + +* March 30, 2004 +- Dominick Meglio's new ares_expand_string. A helper function when decoding + incoming DNS packages. + +- Daniel Stenberg modified the Makefile.in to use a for loop for the man page + installation to improve overview and make it easier to add man pages. + +Version 1.1.0 (March 11, 2004) + +* March 9, 2004 +- Gisle Vanem improved build on Windows. + +* February 25, 2004 +- Dan Fandrich found a flaw in the Feb 22 fix. + +- Added better configure --enable-debug logic (taken from the curl configure + script). Added acinclude.m4 to the tarball. + +* February 23, 2004 +- Removed ares_free_errmem(), the function, the file and the man page. It was + not used and it did nothing. + +- Fixed a lot of code that wasn't "64bit clean" and thus caused a lot of + compiler warnings on picky compilers. + +* February 22, 2004 +- Dominick Meglio made ares init support multiple name servers in the + NameServer key on Windows. + +* February 16, 2004 +- Modified ares_private.h to include libcurl's memory debug header if + CURLDEBUG is set. This makes all the ares-functions supervised properly by + the curl test suite. This also forced me to add inclusion of the + ares_private.h header in a few more files that are using some kind of + memory-related resources. + +- Made the makefile only build ahost and adig if 'make demos' is used. + +* February 10, 2004 +- Dirk Manske made ares_version.h installed with 'make install' + +* February 4, 2004 +- ares_free_errmem() is subject for removal, it is simply present for future + purposes, and since we removed the extra parameter in strerror() it won't + be used by c-ares! +- configure --enable-debug now enables picky compiler options if gcc is used +- fixed several compiler warnings --enable-debug showed and Joerg Mueller-Tolk + reported + +Version 1.0.0 (February 3, 2004) + +* February 3, 2004 +- now we produce the libcares.a library instead of the previous libares.a + since we are no longer compatible + +* February 2, 2004 + +- ares_strerror() has one argument less. This is the first official + modification of the existing provided ares API. + +* January 29, 2004 + +- Dirk Manske fixed how the socket is set non-blocking. + +* January 4, 2004 + +- Dominick Meglio made the private gettimeofday() become ares_gettimeofday() + instead in order to not pollute the name space and risk colliding with + other libraries' versions of this function. + +* October 24, 2003. Daniel Stenberg + + Added ares_version(). + +Version 1.0-pre1 (8 October 2003) + +- James Bursa made it run on RISC OS + +- Dominick Meglio made it run fine on NT4 + +- Duncan Wilcox made it work fine on Mac OS X + +- Daniel Stenberg adjusted the windows port + +- liren at vivisimo.com made the initial windows port + +* Imported the sources from ares 1.1.1 diff --git a/deps/c-ares/NEWS b/deps/c-ares/NEWS new file mode 100644 index 00000000000..95a2eeea274 --- /dev/null +++ b/deps/c-ares/NEWS @@ -0,0 +1,21 @@ +Major changes since: +* see the CHANGES file + +Major changes in release 1.1.1: +* ares should now compile as C++ code (no longer uses reserved word + "class"). +* Added SRV support to adig test program. +* Fixed a few error handling bugs in query processing. + +Major changes in release 1.1.0: +* Added ares_free_string() function so that memory can be freed in the + same layer as it is allocated, a desirable feature in some + environments. +* A few of the ares_dns.h macros are fixed to use the proper bitwise + operator. +* Fixed a couple of fenceposts fixed in ares_expand_name()'s + bounds-checking. +* In process_timeouts(), extract query->next before calling + next_server() and possibly freeing the query structure. +* Casted arguments to ctype macros casted to unsigned char, since not + all char values are valid inputs to those macros according to ANSI. diff --git a/deps/c-ares/README b/deps/c-ares/README new file mode 100644 index 00000000000..aae99cdf78d --- /dev/null +++ b/deps/c-ares/README @@ -0,0 +1,60 @@ +c-ares +====== + +This is c-ares, an asynchronous resolver library. It is intended for +applications which need to perform DNS queries without blocking, or need to +perform multiple DNS queries in parallel. The primary examples of such +applications are servers which communicate with multiple clients and programs +with graphical user interfaces. + +The full source code is available in the 'c-ares' release archives, and in a +git repository: http://github.com/bagder/c-ares + +If you find bugs, correct flaws, have questions or have comments in general in +regard to c-ares (or by all means the original ares too), get in touch with us +on the c-ares mailing list: http://cool.haxx.se/mailman/listinfo/c-ares + +c-ares is of course distributed under the same MIT-style license as the +original ares. + +You'll find all c-ares details and news here: + + http://c-ares.haxx.se/ + + +NOTES FOR C-ARES HACKERS + +The following notes apply to c-ares version 1.7.0 and later. + +* The distributed ares_build.h file is only intended to be used on systems + which can not run the also distributed configure script. + +* The distributed ares_build.h file is generated as a copy of ares_build.h.dist + when the c-ares source code distribution archive file is originally created. + +* If you check out from git on a non-configure platform, you must run the + appropriate buildconf* script to set up ares_build.h and other local files + before being able of compiling the library. + +* On systems capable of running the configure script, the configure process + will overwrite the distributed ares_build.h file with one that is suitable + and specific to the library being configured and built, this new file is + generated from the ares_build.h.in template file. + +* If you intend to distribute an already compiled c-ares library you _MUST_ + also distribute along with it the generated ares_build.h which has been + used to compile it. Otherwise the library will be of no use for the users of + the library that you have built. It is _your_ responsability to provide this + file. No one at the c-ares project can know how you have built the library. + +* File ares_build.h includes platform and configuration dependent info, + and must not be modified by anyone. Configure script generates it for you. + +* We cannot assume anything else but very basic compiler features being + present. While c-ares requires an ANSI C compiler to build, some of the + earlier ANSI compilers clearly can't deal with some preprocessor operators. + +* Newlines must remain unix-style for older compilers' sake. + +* Comments must be written in the old-style /* unnested C-fashion */ + diff --git a/deps/c-ares/README.cares b/deps/c-ares/README.cares new file mode 100644 index 00000000000..aca54c8cd1f --- /dev/null +++ b/deps/c-ares/README.cares @@ -0,0 +1,13 @@ +c-ares +====== + +This package is based on ares 1.1.1 (written by Greg Hudson). I decided to +fork and release a separate project since the ares author didn't want the +improvements that were vital for our use of it. + +This package is dubbed 'c-ares' since I (Daniel Stenberg) wanted this for use +within the curl project (hence the letter C) and it makes a nice pun. Also, +c-ares is not API compatible with ares: a new name makes that more obvious to +the public. + +The original libares was distributed at athena-dist.mit.edu:pub/ATHENA/ares. diff --git a/deps/c-ares/README.msvc b/deps/c-ares/README.msvc new file mode 100644 index 00000000000..2c63085a0bb --- /dev/null +++ b/deps/c-ares/README.msvc @@ -0,0 +1,119 @@ + $Id$ + + + ___ __ _ _ __ ___ ___ + / __| ___ / _` | '__/ _ \/ __| + | (_ |___| (_| | | | __/\__ \ + \___| \__,_|_| \___||___/ + + + How to build c-ares using MSVC or Visual Studio + ================================================= + + + + How to build using MSVC from the command line + --------------------------------------------- + + Open a command prompt window and ensure that the environment is properly + set up in order to use MSVC or Visual Studio compiler tools. + + Change to c-ares source folder where Makefile.msvc file is located and run: + + > nmake -f Makefile.msvc + + This will build all c-ares libraries as well as three sample programs. + + Once the above command has finished a new folder named MSVCXX will exist + below the folder where makefile.msvc is found. The name of the folder + depends on the MSVC compiler version being used to build c-ares. + + Below the MSVCXX folder there will exist four folders named 'cares', + 'ahost', 'acountry', and 'adig'. The 'cares' folder is the one that + holds the c-ares libraries you have just generated, the other three + hold sample programs that use the libraries. + + The above command builds four versions of the c-ares library, dynamic + and static versions and each one in release and debug flavours. Each + of these is found in folders named dll-release, dll-debug, lib-release, + and lib-debug, which hang from the 'cares' folder mentioned above. Each + sample program also has folders with the same names to reflect which + library version it is using. + + + How to build using Visual Studio 6 IDE + -------------------------------------- + + A VC++ 6.0 reference workspace (vc6aws.dsw) is available within the 'vc' + folder to allow proper building of the library and sample programs. + + 1) Open the vc6aws.dsw workspace with MSVC6's IDE. + 2) Select 'Build' from top menu. + 3) Select 'Batch Build' from dropdown menu. + 4) Make sure that the sixteen project configurations are 'checked'. + 5) Click on the 'Build' button. + 6) Once the sixteen project configurations are built you are done. + + Dynamic and static c-ares libraries are built in debug and release flavours, + and can be located each one in its own subdirectory, dll-debug, dll-release, + lib-debug and lib-release, all of them below the 'vc\cares' subdirectory. + + In the same way four executable versions of each sample program are built, + each using its respective library. The resulting sample executables are + located in its own subdirectory, dll-debug, dll-release, lib-debug and + lib-release, below the 'vc\acountry', 'vc\adig' and 'vc\ahost'folders. + + These reference VC++ 6.0 configurations are generated using the dynamic CRT. + + + How to build using Visual Studio 2003 or newer IDE + -------------------------------------------------- + + First you have to convert the VC++ 6.0 reference workspace and project files + to the Visual Studio IDE version you are using, following next steps: + + 1) Open vc\vc6aws.dsw with VS20XX. + 2) Allow VS20XX to update all projects and workspaces. + 3) Save ALL and close VS20XX. + 4) Open vc\vc6aws.sln with VS20XX. + 5) Select batch build, check 'all' projects and click 'build' button. + + Same comments relative to generated files and folders as done above for + Visual Studio 6 IDE apply here. + + + Relationship between c-ares library file names and versions + ----------------------------------------------------------- + + c-ares static release library version files: + + libcares.lib -> static release library + + c-ares static debug library version files: + + libcaresd.lib -> static debug library + + c-ares dynamic release library version files: + + cares.dll -> dynamic release library + cares.lib -> import library for the dynamic release library + cares.exp -> export file for the dynamic release library + + c-ares dynamic debug library version files: + + caresd.dll -> dynamic debug library + caresd.lib -> import library for the dynamic debug library + caresd.exp -> export file for the dynamic debug library + caresd.pdb -> debug symbol file for the dynamic debug library + + + How to use c-ares static libraries + ---------------------------------- + + When using the c-ares static library in your program, you will have to + define preprocessor symbol CARES_STATICLIB while building your program, + otherwise you will get errors at linkage stage. + + +Have Fun! + diff --git a/deps/c-ares/README.node b/deps/c-ares/README.node new file mode 100644 index 00000000000..e37a153acb6 --- /dev/null +++ b/deps/c-ares/README.node @@ -0,0 +1,21 @@ +Library: c-ares, DNS resolver + +Version: 1.7.1 (23 march, 2010) + +Authors: Greg Hudson, Daniel Stenberg + +License: MIT + +Notes: + +Just use waf instead of the autoconf based configure script. Delete most of +the documentation and other files distributed with it. To upgrade, run +./configure on linux, macintosh, solaris (and other supported platforms) and +copy +- ares_config.h +- ares_setup.h +- ares_build.h +into the appropriate directory. + + + diff --git a/deps/c-ares/RELEASE-NOTES b/deps/c-ares/RELEASE-NOTES new file mode 100644 index 00000000000..0e1fefb4c8b --- /dev/null +++ b/deps/c-ares/RELEASE-NOTES @@ -0,0 +1,18 @@ +This is what's new and changed in the c-ares 1.7.1 release: + +Changed: + + o added IPv6 name servers support + +Fixed: + + o closing of sockets on Windows systems + o MSVC deprecated compiler options warnings + o ares_process_fd() didn't check broken connections + +Thanks go to these friendly people for their efforts and contributions: + + Ingmar Runge, Laszlo Tamas Szabo, Yang Tse, Tommie Gannert, Gregor Jasny, + Phil Blundell, Cedric Bail, Jakub Hrozek + +Have fun! diff --git a/deps/c-ares/TODO b/deps/c-ares/TODO new file mode 100644 index 00000000000..fa31cea6fb7 --- /dev/null +++ b/deps/c-ares/TODO @@ -0,0 +1,23 @@ +TODO +==== + +ares_reinit() + +- To allow an app to force a re-read of /etc/resolv.conf etc, pretty much + like the res_init() resolver function offers + +ares_gethostbyname + +- When built to support IPv6, it needs to also support PF_UNSPEC or similar, + so that an application can ask for any protocol and then c-ares would return + all known resolves and not just explicitly IPv4 _or_ IPv6 resolves. + +ares_process + +- Upon next ABI breakage ares_process() should be changed to return 'int' + and return ARES_ENOTINITIALIZED if ares_library_init() has not been called. + +ares_process_fd + +- Upon next ABI breakage ares_process_fd() should be changed to return + 'int' and return ARES_ENOTINITIALIZED if library has not been initialized. diff --git a/deps/c-ares/ares.h b/deps/c-ares/ares.h new file mode 100644 index 00000000000..6d658ad2d32 --- /dev/null +++ b/deps/c-ares/ares.h @@ -0,0 +1,509 @@ +/* $Id$ */ + +/* Copyright 1998, 2009 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef ARES__H +#define ARES__H + +#include "ares_version.h" /* c-ares version defines */ +#include "ares_build.h" /* c-ares build definitions */ +#include "ares_rules.h" /* c-ares rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +# define WIN32 +#endif + +#include + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on system that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) +#include +#endif +#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) +#include +#endif + +#if defined(WATT32) +# include +# include +# include +#elif defined(WIN32) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#else +# include +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** c-ares external API function linkage decorations. +*/ + +#if !defined(CARES_STATICLIB) && \ + (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) + /* __declspec function decoration for Win32 and Symbian DLL's */ +# if defined(CARES_BUILDING_LIBRARY) +# define CARES_EXTERN __declspec(dllexport) +# else +# define CARES_EXTERN __declspec(dllimport) +# endif +#else + /* visibility function decoration for other cases */ +# if !defined(CARES_SYMBOL_HIDING) || \ + defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# define CARES_EXTERN +# else +# define CARES_EXTERN CARES_SYMBOL_SCOPE_EXTERN +# endif +#endif + + +#define ARES_SUCCESS 0 + +/* Server error codes (ARES_ENODATA indicates no relevant answer) */ +#define ARES_ENODATA 1 +#define ARES_EFORMERR 2 +#define ARES_ESERVFAIL 3 +#define ARES_ENOTFOUND 4 +#define ARES_ENOTIMP 5 +#define ARES_EREFUSED 6 + +/* Locally generated error codes */ +#define ARES_EBADQUERY 7 +#define ARES_EBADNAME 8 +#define ARES_EBADFAMILY 9 +#define ARES_EBADRESP 10 +#define ARES_ECONNREFUSED 11 +#define ARES_ETIMEOUT 12 +#define ARES_EOF 13 +#define ARES_EFILE 14 +#define ARES_ENOMEM 15 +#define ARES_EDESTRUCTION 16 +#define ARES_EBADSTR 17 + +/* ares_getnameinfo error codes */ +#define ARES_EBADFLAGS 18 + +/* ares_getaddrinfo error codes */ +#define ARES_ENONAME 19 +#define ARES_EBADHINTS 20 + +/* Uninitialized library error code */ +#define ARES_ENOTINITIALIZED 21 /* introduced in 1.7.0 */ + +/* ares_library_init error codes */ +#define ARES_ELOADIPHLPAPI 22 /* introduced in 1.7.0 */ +#define ARES_EADDRGETNETWORKPARAMS 23 /* introduced in 1.7.0 */ + +/* More error codes */ +#define ARES_ECANCELLED 24 /* introduced in 1.7.0 */ + +/* Flag values */ +#define ARES_FLAG_USEVC (1 << 0) +#define ARES_FLAG_PRIMARY (1 << 1) +#define ARES_FLAG_IGNTC (1 << 2) +#define ARES_FLAG_NORECURSE (1 << 3) +#define ARES_FLAG_STAYOPEN (1 << 4) +#define ARES_FLAG_NOSEARCH (1 << 5) +#define ARES_FLAG_NOALIASES (1 << 6) +#define ARES_FLAG_NOCHECKRESP (1 << 7) + +/* Option mask values */ +#define ARES_OPT_FLAGS (1 << 0) +#define ARES_OPT_TIMEOUT (1 << 1) +#define ARES_OPT_TRIES (1 << 2) +#define ARES_OPT_NDOTS (1 << 3) +#define ARES_OPT_UDP_PORT (1 << 4) +#define ARES_OPT_TCP_PORT (1 << 5) +#define ARES_OPT_SERVERS (1 << 6) +#define ARES_OPT_DOMAINS (1 << 7) +#define ARES_OPT_LOOKUPS (1 << 8) +#define ARES_OPT_SOCK_STATE_CB (1 << 9) +#define ARES_OPT_SORTLIST (1 << 10) +#define ARES_OPT_SOCK_SNDBUF (1 << 11) +#define ARES_OPT_SOCK_RCVBUF (1 << 12) +#define ARES_OPT_TIMEOUTMS (1 << 13) +#define ARES_OPT_ROTATE (1 << 14) + +/* Nameinfo flag values */ +#define ARES_NI_NOFQDN (1 << 0) +#define ARES_NI_NUMERICHOST (1 << 1) +#define ARES_NI_NAMEREQD (1 << 2) +#define ARES_NI_NUMERICSERV (1 << 3) +#define ARES_NI_DGRAM (1 << 4) +#define ARES_NI_TCP 0 +#define ARES_NI_UDP ARES_NI_DGRAM +#define ARES_NI_SCTP (1 << 5) +#define ARES_NI_DCCP (1 << 6) +#define ARES_NI_NUMERICSCOPE (1 << 7) +#define ARES_NI_LOOKUPHOST (1 << 8) +#define ARES_NI_LOOKUPSERVICE (1 << 9) +/* Reserved for future use */ +#define ARES_NI_IDN (1 << 10) +#define ARES_NI_IDN_ALLOW_UNASSIGNED (1 << 11) +#define ARES_NI_IDN_USE_STD3_ASCII_RULES (1 << 12) + +/* Addrinfo flag values */ +#define ARES_AI_CANONNAME (1 << 0) +#define ARES_AI_NUMERICHOST (1 << 1) +#define ARES_AI_PASSIVE (1 << 2) +#define ARES_AI_NUMERICSERV (1 << 3) +#define ARES_AI_V4MAPPED (1 << 4) +#define ARES_AI_ALL (1 << 5) +#define ARES_AI_ADDRCONFIG (1 << 6) +/* Reserved for future use */ +#define ARES_AI_IDN (1 << 10) +#define ARES_AI_IDN_ALLOW_UNASSIGNED (1 << 11) +#define ARES_AI_IDN_USE_STD3_ASCII_RULES (1 << 12) +#define ARES_AI_CANONIDN (1 << 13) + +#define ARES_AI_MASK (ARES_AI_CANONNAME|ARES_AI_NUMERICHOST|ARES_AI_PASSIVE| \ + ARES_AI_NUMERICSERV|ARES_AI_V4MAPPED|ARES_AI_ALL| \ + ARES_AI_ADDRCONFIG) +#define ARES_GETSOCK_MAXNUM 16 /* ares_getsock() can return info about this + many sockets */ +#define ARES_GETSOCK_READABLE(bits,num) (bits & (1<< (num))) +#define ARES_GETSOCK_WRITABLE(bits,num) (bits & (1 << ((num) + \ + ARES_GETSOCK_MAXNUM))) + +/* c-ares library initialization flag values */ +#define ARES_LIB_INIT_NONE (0) +#define ARES_LIB_INIT_WIN32 (1 << 0) +#define ARES_LIB_INIT_ALL (ARES_LIB_INIT_WIN32) + + +/* + * Typedef our socket type + */ + +#ifndef ares_socket_typedef +#ifdef WIN32 +typedef SOCKET ares_socket_t; +#define ARES_SOCKET_BAD INVALID_SOCKET +#else +typedef int ares_socket_t; +#define ARES_SOCKET_BAD -1 +#endif +#define ares_socket_typedef +#endif /* ares_socket_typedef */ + +typedef void (*ares_sock_state_cb)(void *data, + ares_socket_t socket_fd, + int readable, + int writable); + +struct apattern; + +/* NOTE about the ares_options struct to users and developers. + + This struct will remain looking like this. It will not be extended nor + shrunk in future releases, but all new options will be set by ares_set_*() + options instead of with the ares_init_options() function. + + Eventually (in a galaxy far far away), all options will be settable by + ares_set_*() options and the ares_init_options() function will become + deprecated. + + When new options are added to c-ares, they are not added to this + struct. And they are not "saved" with the ares_save_options() function but + instead we encourage the use of the ares_dup() function. Needless to say, + if you add config options to c-ares you need to make sure ares_dup() + duplicates this new option. + + */ +struct ares_options { + int flags; + int timeout; /* in seconds or milliseconds, depending on options */ + int tries; + int ndots; + unsigned short udp_port; + unsigned short tcp_port; + int socket_send_buffer_size; + int socket_receive_buffer_size; + struct in_addr *servers; + int nservers; + char **domains; + int ndomains; + char *lookups; + ares_sock_state_cb sock_state_cb; + void *sock_state_cb_data; + struct apattern *sortlist; + int nsort; +}; + +struct hostent; +struct timeval; +struct sockaddr; +struct ares_channeldata; + +typedef struct ares_channeldata *ares_channel; + +typedef void (*ares_callback)(void *arg, + int status, + int timeouts, + unsigned char *abuf, + int alen); + +typedef void (*ares_host_callback)(void *arg, + int status, + int timeouts, + struct hostent *hostent); + +typedef void (*ares_nameinfo_callback)(void *arg, + int status, + int timeouts, + char *node, + char *service); + +typedef int (*ares_sock_create_callback)(ares_socket_t socket_fd, + int type, + void *data); + +CARES_EXTERN int ares_library_init(int flags); + +CARES_EXTERN void ares_library_cleanup(void); + +CARES_EXTERN const char *ares_version(int *version); + +CARES_EXTERN int ares_init(ares_channel *channelptr); + +CARES_EXTERN int ares_init_options(ares_channel *channelptr, + struct ares_options *options, + int optmask); + +CARES_EXTERN int ares_save_options(ares_channel channel, + struct ares_options *options, + int *optmask); + +CARES_EXTERN void ares_destroy_options(struct ares_options *options); + +CARES_EXTERN int ares_dup(ares_channel *dest, + ares_channel src); + +CARES_EXTERN void ares_destroy(ares_channel channel); + +CARES_EXTERN void ares_cancel(ares_channel channel); + +CARES_EXTERN void ares_set_socket_callback(ares_channel channel, + ares_sock_create_callback callback, + void *user_data); + +CARES_EXTERN void ares_send(ares_channel channel, + const unsigned char *qbuf, + int qlen, + ares_callback callback, + void *arg); + +CARES_EXTERN void ares_query(ares_channel channel, + const char *name, + int dnsclass, + int type, + ares_callback callback, + void *arg); + +CARES_EXTERN void ares_search(ares_channel channel, + const char *name, + int dnsclass, + int type, + ares_callback callback, + void *arg); + +CARES_EXTERN void ares_gethostbyname(ares_channel channel, + const char *name, + int family, + ares_host_callback callback, + void *arg); + +CARES_EXTERN int ares_gethostbyname_file(ares_channel channel, + const char *name, + int family, + struct hostent **host); + +CARES_EXTERN void ares_gethostbyaddr(ares_channel channel, + const void *addr, + int addrlen, + int family, + ares_host_callback callback, + void *arg); + +CARES_EXTERN void ares_getnameinfo(ares_channel channel, + const struct sockaddr *sa, + ares_socklen_t salen, + int flags, + ares_nameinfo_callback callback, + void *arg); + +CARES_EXTERN int ares_fds(ares_channel channel, + fd_set *read_fds, + fd_set *write_fds); + +CARES_EXTERN int ares_getsock(ares_channel channel, + ares_socket_t *socks, + int numsocks); + +CARES_EXTERN struct timeval *ares_timeout(ares_channel channel, + struct timeval *maxtv, + struct timeval *tv); + +CARES_EXTERN void ares_process(ares_channel channel, + fd_set *read_fds, + fd_set *write_fds); + +CARES_EXTERN void ares_process_fd(ares_channel channel, + ares_socket_t read_fd, + ares_socket_t write_fd); + +CARES_EXTERN int ares_mkquery(const char *name, + int dnsclass, + int type, + unsigned short id, + int rd, + unsigned char **buf, + int *buflen); + +CARES_EXTERN int ares_expand_name(const unsigned char *encoded, + const unsigned char *abuf, + int alen, + char **s, + long *enclen); + +CARES_EXTERN int ares_expand_string(const unsigned char *encoded, + const unsigned char *abuf, + int alen, + unsigned char **s, + long *enclen); + +/* + * NOTE: before c-ares 1.7.0 we would most often use the system in6_addr + * struct below when ares itself was built, but many apps would use this + * private version since the header checked a HAVE_* define for it. Starting + * with 1.7.0 we always declare and use our own to stop relying on the + * system's one. + */ +struct ares_in6_addr { + union { + unsigned char _S6_u8[16]; + } _S6_un; +}; + +struct ares_addrttl { + struct in_addr ipaddr; + int ttl; +}; + +struct ares_addr6ttl { + struct ares_in6_addr ip6addr; + int ttl; +}; + +struct ares_srv_reply { + struct ares_srv_reply *next; + char *host; + unsigned short priority; + unsigned short weight; + unsigned short port; +}; + +struct ares_txt_reply { + struct ares_txt_reply *next; + unsigned char *txt; + size_t length; /* length excludes null termination */ +}; + +/* +** Parse the buffer, starting at *abuf and of length alen bytes, previously +** obtained from an ares_search call. Put the results in *host, if nonnull. +** Also, if addrttls is nonnull, put up to *naddrttls IPv4 addresses along with +** their TTLs in that array, and set *naddrttls to the number of addresses +** so written. +*/ + +CARES_EXTERN int ares_parse_a_reply(const unsigned char *abuf, + int alen, + struct hostent **host, + struct ares_addrttl *addrttls, + int *naddrttls); + +CARES_EXTERN int ares_parse_aaaa_reply(const unsigned char *abuf, + int alen, + struct hostent **host, + struct ares_addr6ttl *addrttls, + int *naddrttls); + +CARES_EXTERN int ares_parse_ptr_reply(const unsigned char *abuf, + int alen, + const void *addr, + int addrlen, + int family, + struct hostent **host); + +CARES_EXTERN int ares_parse_ns_reply(const unsigned char *abuf, + int alen, + struct hostent **host); + +CARES_EXTERN int ares_parse_srv_reply(const unsigned char* abuf, + int alen, + struct ares_srv_reply** srv_out); + +CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf, + int alen, + struct ares_txt_reply** txt_out); + +CARES_EXTERN void ares_free_string(void *str); + +CARES_EXTERN void ares_free_hostent(struct hostent *host); + +CARES_EXTERN void ares_free_data(void *dataptr); + +CARES_EXTERN const char *ares_strerror(int code); + +struct ares_addr_node { + struct ares_addr_node *next; + int family; + union { + struct in_addr addr4; + struct ares_in6_addr addr6; + } addr; +}; + +CARES_EXTERN int ares_set_servers(ares_channel channel, + struct ares_addr_node *servers); + +CARES_EXTERN int ares_get_servers(ares_channel channel, + struct ares_addr_node **servers); + +#ifdef __cplusplus +} +#endif + +#endif /* ARES__H */ diff --git a/deps/c-ares/ares__close_sockets.c b/deps/c-ares/ares__close_sockets.c new file mode 100644 index 00000000000..d2476fdbb95 --- /dev/null +++ b/deps/c-ares/ares__close_sockets.c @@ -0,0 +1,67 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "ares.h" +#include "ares_private.h" + +void ares__close_sockets(ares_channel channel, struct server_state *server) +{ + struct send_request *sendreq; + + /* Free all pending output buffers. */ + while (server->qhead) + { + /* Advance server->qhead; pull out query as we go. */ + sendreq = server->qhead; + server->qhead = sendreq->next; + if (sendreq->data_storage != NULL) + free(sendreq->data_storage); + free(sendreq); + } + server->qtail = NULL; + + /* Reset any existing input buffer. */ + if (server->tcp_buffer) + free(server->tcp_buffer); + server->tcp_buffer = NULL; + server->tcp_lenbuf_pos = 0; + + /* Reset brokenness */ + server->is_broken = 0; + + /* Close the TCP and UDP sockets. */ + if (server->tcp_socket != ARES_SOCKET_BAD) + { + SOCK_STATE_CALLBACK(channel, server->tcp_socket, 0, 0); + sclose(server->tcp_socket); + server->tcp_socket = ARES_SOCKET_BAD; + server->tcp_connection_generation = ++channel->tcp_connection_generation; + } + if (server->udp_socket != ARES_SOCKET_BAD) + { + SOCK_STATE_CALLBACK(channel, server->udp_socket, 0, 0); + sclose(server->udp_socket); + server->udp_socket = ARES_SOCKET_BAD; + } +} diff --git a/deps/c-ares/ares__get_hostent.c b/deps/c-ares/ares__get_hostent.c new file mode 100644 index 00000000000..caa7f795bb0 --- /dev/null +++ b/deps/c-ares/ares__get_hostent.c @@ -0,0 +1,264 @@ +/* $Id$ */ + +/* Copyright 1998, 2010 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#include "ares.h" +#include "inet_net_pton.h" +#include "ares_private.h" + +int ares__get_hostent(FILE *fp, int family, struct hostent **host) +{ + char *line = NULL, *p, *q, **alias; + char *txtaddr, *txthost, *txtalias; + int status; + size_t addrlen, linesize, naliases; + struct ares_addr addr; + struct hostent *hostent = NULL; + + *host = NULL; /* Assume failure */ + + /* Validate family */ + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + return ARES_EBADFAMILY; + } + + while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) + { + + /* Trim line comment. */ + p = line; + while (*p && (*p != '#')) + p++; + *p = '\0'; + + /* Trim trailing whitespace. */ + q = p - 1; + while ((q >= line) && ISSPACE(*q)) + q--; + *++q = '\0'; + + /* Skip leading whitespace. */ + p = line; + while (*p && ISSPACE(*p)) + p++; + if (!*p) + /* Ignore line if empty. */ + continue; + + /* Pointer to start of IPv4 or IPv6 address part. */ + txtaddr = p; + + /* Advance past address part. */ + while (*p && !ISSPACE(*p)) + p++; + if (!*p) + /* Ignore line if reached end of line. */ + continue; + + /* Null terminate address part. */ + *p = '\0'; + + /* Advance to host name */ + p++; + while (*p && ISSPACE(*p)) + p++; + if (!*p) + /* Ignore line if reached end of line. */ + continue; + + /* Pointer to start of host name. */ + txthost = p; + + /* Advance past host name. */ + while (*p && !ISSPACE(*p)) + p++; + + /* Pointer to start of first alias. */ + txtalias = NULL; + if (*p) + { + q = p + 1; + while (*q && ISSPACE(*q)) + q++; + if (*q) + txtalias = q; + } + + /* Null terminate host name. */ + *p = '\0'; + + /* find out number of aliases. */ + naliases = 0; + if (txtalias) + { + p = txtalias; + while (*p) + { + while (*p && !ISSPACE(*p)) + p++; + while (*p && ISSPACE(*p)) + p++; + naliases++; + } + } + + /* Convert address string to network address for the requested family. */ + addrlen = 0; + addr.family = AF_UNSPEC; + addr.addrV4.s_addr = INADDR_NONE; + if ((family == AF_INET) || (family == AF_UNSPEC)) + { + addr.addrV4.s_addr = inet_addr(txtaddr); + if (addr.addrV4.s_addr != INADDR_NONE) + { + /* Actual network address family and length. */ + addr.family = AF_INET; + addrlen = sizeof(addr.addrV4); + } + } + if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen))) + { + if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0) + { + /* Actual network address family and length. */ + addr.family = AF_INET6; + addrlen = sizeof(addr.addrV6); + } + } + if (!addrlen) + /* Ignore line if invalid address string for the requested family. */ + continue; + + /* + ** Actual address family possible values are AF_INET and AF_INET6 only. + */ + + /* Allocate memory for the hostent structure. */ + hostent = malloc(sizeof(struct hostent)); + if (!hostent) + break; + + /* Initialize fields for out of memory condition. */ + hostent->h_aliases = NULL; + hostent->h_addr_list = NULL; + + /* Copy official host name. */ + hostent->h_name = strdup(txthost); + if (!hostent->h_name) + break; + + /* Copy network address. */ + hostent->h_addr_list = malloc(2 * sizeof(char *)); + if (!hostent->h_addr_list) + break; + hostent->h_addr_list[1] = NULL; + hostent->h_addr_list[0] = malloc(addrlen); + if (!hostent->h_addr_list[0]) + break; + if (addr.family == AF_INET) + memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4)); + else + memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6)); + + /* Copy aliases. */ + hostent->h_aliases = malloc((naliases + 1) * sizeof(char *)); + if (!hostent->h_aliases) + break; + alias = hostent->h_aliases; + while (naliases) + *(alias + naliases--) = NULL; + *alias = NULL; + while (txtalias) + { + p = txtalias; + while (*p && !ISSPACE(*p)) + p++; + q = p; + while (*q && ISSPACE(*q)) + q++; + *p = '\0'; + if ((*alias = strdup(txtalias)) == NULL) + break; + alias++; + txtalias = *q ? q : NULL; + } + if (txtalias) + /* Alias memory allocation failure. */ + break; + + /* Copy actual network address family and length. */ + hostent->h_addrtype = addr.family; + hostent->h_length = (int)addrlen; + + /* Free line buffer. */ + free(line); + + /* Return hostent successfully */ + *host = hostent; + return ARES_SUCCESS; + + } + + /* If allocated, free line buffer. */ + if (line) + free(line); + + if (status == ARES_SUCCESS) + { + /* Memory allocation failure; clean up. */ + if (hostent) + { + if (hostent->h_name) + free((char *) hostent->h_name); + if (hostent->h_aliases) + { + for (alias = hostent->h_aliases; *alias; alias++) + free(*alias); + free(hostent->h_aliases); + } + if (hostent->h_addr_list) + { + if (hostent->h_addr_list[0]) + free(hostent->h_addr_list[0]); + free(hostent->h_addr_list); + } + free(hostent); + } + return ARES_ENOMEM; + } + + return status; +} diff --git a/deps/c-ares/ares__read_line.c b/deps/c-ares/ares__read_line.c new file mode 100644 index 00000000000..2e94945dc89 --- /dev/null +++ b/deps/c-ares/ares__read_line.c @@ -0,0 +1,72 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include +#include +#include +#include "ares.h" +#include "ares_nowarn.h" +#include "ares_private.h" + +/* This is an internal function. Its contract is to read a line from + * a file into a dynamically allocated buffer, zeroing the trailing + * newline if there is one. The calling routine may call + * ares__read_line multiple times with the same buf and bufsize + * pointers; *buf will be reallocated and *bufsize adjusted as + * appropriate. The initial value of *buf should be NULL. After the + * calling routine is done reading lines, it should free *buf. + */ +int ares__read_line(FILE *fp, char **buf, size_t *bufsize) +{ + char *newbuf; + size_t offset = 0; + size_t len; + + if (*buf == NULL) + { + *buf = malloc(128); + if (!*buf) + return ARES_ENOMEM; + *bufsize = 128; + } + + for (;;) + { + int bytestoread = aresx_uztosi(*bufsize - offset); + + if (!fgets(*buf + offset, bytestoread, fp)) + return (offset != 0) ? 0 : (ferror(fp)) ? ARES_EFILE : ARES_EOF; + len = offset + strlen(*buf + offset); + if ((*buf)[len - 1] == '\n') + { + (*buf)[len - 1] = 0; + break; + } + offset = len; + if(len < *bufsize - 1) + continue; + + /* Allocate more space. */ + newbuf = realloc(*buf, *bufsize * 2); + if (!newbuf) + return ARES_ENOMEM; + *buf = newbuf; + *bufsize *= 2; + } + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares__timeval.c b/deps/c-ares/ares__timeval.c new file mode 100644 index 00000000000..8cf37e91c09 --- /dev/null +++ b/deps/c-ares/ares__timeval.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/* Copyright (C) 2008 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares.h" +#include "ares_private.h" + +#if defined(WIN32) && !defined(MSDOS) + +struct timeval ares__tvnow(void) +{ + /* + ** GetTickCount() is available on _all_ Windows versions from W95 up + ** to nowadays. Returns milliseconds elapsed since last system boot, + ** increases monotonically and wraps once 49.7 days have elapsed. + */ + struct timeval now; + DWORD milliseconds = GetTickCount(); + now.tv_sec = milliseconds / 1000; + now.tv_usec = (milliseconds % 1000) * 1000; + return now; +} + +#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) + +struct timeval ares__tvnow(void) +{ + /* + ** clock_gettime() is granted to be increased monotonically when the + ** monotonic clock is queried. Time starting point is unspecified, it + ** could be the system start-up time, the Epoch, or something else, + ** in any case the time starting point does not change once that the + ** system has started up. + */ + struct timeval now; + struct timespec tsnow; + if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { + now.tv_sec = tsnow.tv_sec; + now.tv_usec = tsnow.tv_nsec / 1000; + } + /* + ** Even when the configure process has truly detected monotonic clock + ** availability, it might happen that it is not actually available at + ** run-time. When this occurs simply fallback to other time source. + */ +#ifdef HAVE_GETTIMEOFDAY + else + (void)gettimeofday(&now, NULL); +#else + else { + now.tv_sec = (long)time(NULL); + now.tv_usec = 0; + } +#endif + return now; +} + +#elif defined(HAVE_GETTIMEOFDAY) + +struct timeval ares__tvnow(void) +{ + /* + ** gettimeofday() is not granted to be increased monotonically, due to + ** clock drifting and external source time synchronization it can jump + ** forward or backward in time. + */ + struct timeval now; + (void)gettimeofday(&now, NULL); + return now; +} + +#else + +struct timeval ares__tvnow(void) +{ + /* + ** time() returns the value of time in seconds since the Epoch. + */ + struct timeval now; + now.tv_sec = (long)time(NULL); + now.tv_usec = 0; + return now; +} + +#endif + +#if 0 /* Not used */ +/* + * Make sure that the first argument is the more recent time, as otherwise + * we'll get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +long ares__tvdiff(struct timeval newer, struct timeval older) +{ + return (newer.tv_sec-older.tv_sec)*1000+ + (newer.tv_usec-older.tv_usec)/1000; +} +#endif + diff --git a/deps/c-ares/ares_cancel.c b/deps/c-ares/ares_cancel.c new file mode 100644 index 00000000000..a730a651ee3 --- /dev/null +++ b/deps/c-ares/ares_cancel.c @@ -0,0 +1,64 @@ +/* $Id$ */ + +/* Copyright (C) 2004 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include +#include +#include "ares.h" +#include "ares_private.h" + +/* + * ares_cancel() cancels all ongoing requests/resolves that might be going on + * on the given channel. It does NOT kill the channel, use ares_destroy() for + * that. + */ +void ares_cancel(ares_channel channel) +{ + struct query *query; + struct list_node* list_head; + struct list_node* list_node; + int i; + + list_head = &(channel->all_queries); + for (list_node = list_head->next; list_node != list_head; ) + { + query = list_node->data; + list_node = list_node->next; /* since we're deleting the query */ + query->callback(query->arg, ARES_ECANCELLED, 0, NULL, 0); + ares__free_query(query); + } +#ifndef NDEBUG + /* Freeing the query should remove it from all the lists in which it sits, + * so all query lists should be empty now. + */ + assert(ares__is_list_empty(&(channel->all_queries))); + for (i = 0; i < ARES_QID_TABLE_SIZE; i++) + { + assert(ares__is_list_empty(&(channel->queries_by_qid[i]))); + } + for (i = 0; i < ARES_TIMEOUT_TABLE_SIZE; i++) + { + assert(ares__is_list_empty(&(channel->queries_by_timeout[i]))); + } +#endif + if (!(channel->flags & ARES_FLAG_STAYOPEN)) + { + if (channel->servers) + { + for (i = 0; i < channel->nservers; i++) + ares__close_sockets(channel, &channel->servers[i]); + } + } +} diff --git a/deps/c-ares/ares_data.c b/deps/c-ares/ares_data.c new file mode 100644 index 00000000000..3a4c00c97d5 --- /dev/null +++ b/deps/c-ares/ares_data.c @@ -0,0 +1,176 @@ +/* $Id$ */ + +/* Copyright (C) 2009-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +#include "ares_setup.h" + +#include + +#include "ares.h" +#include "ares_data.h" +#include "ares_private.h" + + +/* +** ares_free_data() - c-ares external API function. +** +** This function must be used by the application to free data memory that +** has been internally allocated by some c-ares function and for which a +** pointer has already been returned to the calling application. The list +** of c-ares functions returning pointers that must be free'ed using this +** function is: +** +** ares_get_servers() +** ares_parse_srv_reply() +** ares_parse_txt_reply() +*/ + +void ares_free_data(void *dataptr) +{ + struct ares_data *ptr; + + if (!dataptr) + return; + +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:1684) + /* 1684: conversion from pointer to same-sized integral type */ +#endif + + ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data)); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif + + if (ptr->mark != ARES_DATATYPE_MARK) + return; + + switch (ptr->type) + { + case ARES_DATATYPE_SRV_REPLY: + + if (ptr->data.srv_reply.next) + ares_free_data(ptr->data.srv_reply.next); + if (ptr->data.srv_reply.host) + free(ptr->data.srv_reply.host); + break; + + case ARES_DATATYPE_TXT_REPLY: + + if (ptr->data.txt_reply.next) + ares_free_data(ptr->data.txt_reply.next); + if (ptr->data.txt_reply.txt) + free(ptr->data.txt_reply.txt); + break; + + case ARES_DATATYPE_ADDR_NODE: + + if (ptr->data.addr_node.next) + ares_free_data(ptr->data.addr_node.next); + break; + + default: + return; + } + + free(ptr); +} + + +/* +** ares_malloc_data() - c-ares internal helper function. +** +** This function allocates memory for a c-ares private ares_data struct +** for the specified ares_datatype, initializes c-ares private fields +** and zero initializes those which later might be used from the public +** API. It returns an interior pointer which can be passed by c-ares +** functions to the calling application, and that must be free'ed using +** c-ares external API function ares_free_data(). +*/ + +void *ares_malloc_data(ares_datatype type) +{ + struct ares_data *ptr; + + ptr = malloc(sizeof(struct ares_data)); + if (!ptr) + return NULL; + + switch (type) + { + case ARES_DATATYPE_SRV_REPLY: + ptr->data.srv_reply.next = NULL; + ptr->data.srv_reply.host = NULL; + ptr->data.srv_reply.priority = 0; + ptr->data.srv_reply.weight = 0; + ptr->data.srv_reply.port = 0; + break; + + case ARES_DATATYPE_TXT_REPLY: + ptr->data.txt_reply.next = NULL; + ptr->data.txt_reply.txt = NULL; + ptr->data.txt_reply.length = 0; + break; + + case ARES_DATATYPE_ADDR_NODE: + ptr->data.addr_node.next = NULL; + ptr->data.addr_node.family = 0; + memset(&ptr->data.addr_node.addrV6, 0, + sizeof(ptr->data.addr_node.addrV6)); + + default: + free(ptr); + return NULL; + } + + ptr->mark = ARES_DATATYPE_MARK; + ptr->type = type; + + return &ptr->data; +} + + +/* +** ares_get_datatype() - c-ares internal helper function. +** +** This function returns the ares_datatype of the data stored in a +** private ares_data struct when given the public API pointer. +*/ + +ares_datatype ares_get_datatype(void * dataptr) +{ + struct ares_data *ptr; + +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:1684) + /* 1684: conversion from pointer to same-sized integral type */ +#endif + + ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data)); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif + + if (ptr->mark == ARES_DATATYPE_MARK) + return ptr->type; + + return ARES_DATATYPE_UNKNOWN; +} diff --git a/deps/c-ares/ares_data.h b/deps/c-ares/ares_data.h new file mode 100644 index 00000000000..02ff1bca522 --- /dev/null +++ b/deps/c-ares/ares_data.h @@ -0,0 +1,64 @@ +/* $Id$ */ + +/* Copyright (C) 2009-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +typedef enum { + ARES_DATATYPE_UNKNOWN = 1, /* unknown data type - introduced in 1.7.0 */ + ARES_DATATYPE_SRV_REPLY, /* struct ares_srv_reply - introduced in 1.7.0 */ + ARES_DATATYPE_TXT_REPLY, /* struct ares_txt_reply - introduced in 1.7.0 */ + ARES_DATATYPE_ADDR_NODE, /* struct ares_addr_node - introduced in 1.7.1 */ +#if 0 + ARES_DATATYPE_ADDR6TTL, /* struct ares_addrttl */ + ARES_DATATYPE_ADDRTTL, /* struct ares_addr6ttl */ + ARES_DATATYPE_HOSTENT, /* struct hostent */ + ARES_DATATYPE_OPTIONS, /* struct ares_options */ +#endif + ARES_DATATYPE_LAST /* not used - introduced in 1.7.0 */ +} ares_datatype; + +#define ARES_DATATYPE_MARK 0xbead + +/* + * ares_data struct definition is internal to c-ares and shall not + * be exposed by the public API in order to allow future changes + * and extensions to it without breaking ABI. This will be used + * internally by c-ares as the container of multiple types of data + * dynamically allocated for which a reference will be returned + * to the calling application. + * + * c-ares API functions returning a pointer to c-ares internally + * allocated data will actually be returning an interior pointer + * into this ares_data struct. + * + * All this is 'invisible' to the calling application, the only + * requirement is that this kind of data must be free'ed by the + * calling application using ares_free_data() with the pointer + * it has received from a previous c-ares function call. + */ + +struct ares_data { + ares_datatype type; /* Actual data type identifier. */ + unsigned int mark; /* Private ares_data signature. */ + union { + struct ares_txt_reply txt_reply; + struct ares_srv_reply srv_reply; + struct ares_addr_node addr_node; + } data; +}; + +void *ares_malloc_data(ares_datatype type); + +ares_datatype ares_get_datatype(void * dataptr); diff --git a/deps/c-ares/ares_destroy.c b/deps/c-ares/ares_destroy.c new file mode 100644 index 00000000000..d9216668fc4 --- /dev/null +++ b/deps/c-ares/ares_destroy.c @@ -0,0 +1,106 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2004-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include +#include +#include "ares.h" +#include "ares_private.h" + +void ares_destroy_options(struct ares_options *options) +{ + int i; + + if(options->servers) + free(options->servers); + for (i = 0; i < options->ndomains; i++) + free(options->domains[i]); + free(options->domains); + if(options->sortlist) + free(options->sortlist); + free(options->lookups); +} + +void ares_destroy(ares_channel channel) +{ + int i; + struct query *query; + struct list_node* list_head; + struct list_node* list_node; + + if (!channel) + return; + + list_head = &(channel->all_queries); + for (list_node = list_head->next; list_node != list_head; ) + { + query = list_node->data; + list_node = list_node->next; /* since we're deleting the query */ + query->callback(query->arg, ARES_EDESTRUCTION, 0, NULL, 0); + ares__free_query(query); + } +#ifndef NDEBUG + /* Freeing the query should remove it from all the lists in which it sits, + * so all query lists should be empty now. + */ + assert(ares__is_list_empty(&(channel->all_queries))); + for (i = 0; i < ARES_QID_TABLE_SIZE; i++) + { + assert(ares__is_list_empty(&(channel->queries_by_qid[i]))); + } + for (i = 0; i < ARES_TIMEOUT_TABLE_SIZE; i++) + { + assert(ares__is_list_empty(&(channel->queries_by_timeout[i]))); + } +#endif + + ares__destroy_servers_state(channel); + + if (channel->domains) { + for (i = 0; i < channel->ndomains; i++) + free(channel->domains[i]); + free(channel->domains); + } + + if(channel->sortlist) + free(channel->sortlist); + + if (channel->lookups) + free(channel->lookups); + + free(channel); +} + +void ares__destroy_servers_state(ares_channel channel) +{ + struct server_state *server; + int i; + + if (channel->servers) + { + for (i = 0; i < channel->nservers; i++) + { + server = &channel->servers[i]; + ares__close_sockets(channel, server); + assert(ares__is_list_empty(&server->queries_to_server)); + } + free(channel->servers); + channel->servers = NULL; + } + channel->nservers = -1; +} diff --git a/deps/c-ares/ares_dns.h b/deps/c-ares/ares_dns.h new file mode 100644 index 00000000000..2187da6e3f3 --- /dev/null +++ b/deps/c-ares/ares_dns.h @@ -0,0 +1,91 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef ARES__DNS_H +#define ARES__DNS_H + +#define DNS__16BIT(p) (((p)[0] << 8) | (p)[1]) +#define DNS__32BIT(p) (((p)[0] << 24) | ((p)[1] << 16) | \ + ((p)[2] << 8) | (p)[3]) + +#define DNS__SET16BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 8) & 0xff)), \ + ((p)[1] = (unsigned char)((v) & 0xff))) +#define DNS__SET32BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 24) & 0xff)), \ + ((p)[1] = (unsigned char)(((v) >> 16) & 0xff)), \ + ((p)[2] = (unsigned char)(((v) >> 8) & 0xff)), \ + ((p)[3] = (unsigned char)((v) & 0xff))) + +#if 0 +/* we cannot use this approach on systems where we can't access 16/32 bit + data on un-aligned addresses */ +#define DNS__16BIT(p) ntohs(*(unsigned short*)(p)) +#define DNS__32BIT(p) ntohl(*(unsigned long*)(p)) +#define DNS__SET16BIT(p, v) *(unsigned short*)(p) = htons(v) +#define DNS__SET32BIT(p, v) *(unsigned long*)(p) = htonl(v) +#endif + +/* Macros for parsing a DNS header */ +#define DNS_HEADER_QID(h) DNS__16BIT(h) +#define DNS_HEADER_QR(h) (((h)[2] >> 7) & 0x1) +#define DNS_HEADER_OPCODE(h) (((h)[2] >> 3) & 0xf) +#define DNS_HEADER_AA(h) (((h)[2] >> 2) & 0x1) +#define DNS_HEADER_TC(h) (((h)[2] >> 1) & 0x1) +#define DNS_HEADER_RD(h) ((h)[2] & 0x1) +#define DNS_HEADER_RA(h) (((h)[3] >> 7) & 0x1) +#define DNS_HEADER_Z(h) (((h)[3] >> 4) & 0x7) +#define DNS_HEADER_RCODE(h) ((h)[3] & 0xf) +#define DNS_HEADER_QDCOUNT(h) DNS__16BIT((h) + 4) +#define DNS_HEADER_ANCOUNT(h) DNS__16BIT((h) + 6) +#define DNS_HEADER_NSCOUNT(h) DNS__16BIT((h) + 8) +#define DNS_HEADER_ARCOUNT(h) DNS__16BIT((h) + 10) + +/* Macros for constructing a DNS header */ +#define DNS_HEADER_SET_QID(h, v) DNS__SET16BIT(h, v) +#define DNS_HEADER_SET_QR(h, v) ((h)[2] |= (unsigned char)(((v) & 0x1) << 7)) +#define DNS_HEADER_SET_OPCODE(h, v) ((h)[2] |= (unsigned char)(((v) & 0xf) << 3)) +#define DNS_HEADER_SET_AA(h, v) ((h)[2] |= (unsigned char)(((v) & 0x1) << 2)) +#define DNS_HEADER_SET_TC(h, v) ((h)[2] |= (unsigned char)(((v) & 0x1) << 1)) +#define DNS_HEADER_SET_RD(h, v) ((h)[2] |= (unsigned char)((v) & 0x1)) +#define DNS_HEADER_SET_RA(h, v) ((h)[3] |= (unsigned char)(((v) & 0x1) << 7)) +#define DNS_HEADER_SET_Z(h, v) ((h)[3] |= (unsigned char)(((v) & 0x7) << 4)) +#define DNS_HEADER_SET_RCODE(h, v) ((h)[3] |= (unsigned char)((v) & 0xf)) +#define DNS_HEADER_SET_QDCOUNT(h, v) DNS__SET16BIT((h) + 4, v) +#define DNS_HEADER_SET_ANCOUNT(h, v) DNS__SET16BIT((h) + 6, v) +#define DNS_HEADER_SET_NSCOUNT(h, v) DNS__SET16BIT((h) + 8, v) +#define DNS_HEADER_SET_ARCOUNT(h, v) DNS__SET16BIT((h) + 10, v) + +/* Macros for parsing the fixed part of a DNS question */ +#define DNS_QUESTION_TYPE(q) DNS__16BIT(q) +#define DNS_QUESTION_CLASS(q) DNS__16BIT((q) + 2) + +/* Macros for constructing the fixed part of a DNS question */ +#define DNS_QUESTION_SET_TYPE(q, v) DNS__SET16BIT(q, v) +#define DNS_QUESTION_SET_CLASS(q, v) DNS__SET16BIT((q) + 2, v) + +/* Macros for parsing the fixed part of a DNS resource record */ +#define DNS_RR_TYPE(r) DNS__16BIT(r) +#define DNS_RR_CLASS(r) DNS__16BIT((r) + 2) +#define DNS_RR_TTL(r) DNS__32BIT((r) + 4) +#define DNS_RR_LEN(r) DNS__16BIT((r) + 8) + +/* Macros for constructing the fixed part of a DNS resource record */ +#define DNS_RR_SET_TYPE(r) DNS__SET16BIT(r, v) +#define DNS_RR_SET_CLASS(r) DNS__SET16BIT((r) + 2, v) +#define DNS_RR_SET_TTL(r) DNS__SET32BIT((r) + 4, v) +#define DNS_RR_SET_LEN(r) DNS__SET16BIT((r) + 8, v) + +#endif /* ARES__DNS_H */ diff --git a/deps/c-ares/ares_expand_name.c b/deps/c-ares/ares_expand_name.c new file mode 100644 index 00000000000..fd3220d690d --- /dev/null +++ b/deps/c-ares/ares_expand_name.c @@ -0,0 +1,194 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include "ares.h" +#include "ares_private.h" /* for the memdebug */ + +static int name_length(const unsigned char *encoded, const unsigned char *abuf, + int alen); + +/* Expand an RFC1035-encoded domain name given by encoded. The + * containing message is given by abuf and alen. The result given by + * *s, which is set to a NUL-terminated allocated buffer. *enclen is + * set to the length of the encoded name (not the length of the + * expanded name; the goal is to tell the caller how many bytes to + * move forward to get past the encoded name). + * + * In the simple case, an encoded name is a series of labels, each + * composed of a one-byte length (limited to values between 0 and 63 + * inclusive) followed by the label contents. The name is terminated + * by a zero-length label. + * + * In the more complicated case, a label may be terminated by an + * indirection pointer, specified by two bytes with the high bits of + * the first byte (corresponding to INDIR_MASK) set to 11. With the + * two high bits of the first byte stripped off, the indirection + * pointer gives an offset from the beginning of the containing + * message with more labels to decode. Indirection can happen an + * arbitrary number of times, so we have to detect loops. + * + * Since the expanded name uses '.' as a label separator, we use + * backslashes to escape periods or backslashes in the expanded name. + */ + +int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, + int alen, char **s, long *enclen) +{ + int len, indir = 0; + char *q; + const unsigned char *p; + union { + ssize_t sig; + size_t uns; + } nlen; + + nlen.sig = name_length(encoded, abuf, alen); + if (nlen.sig < 0) + return ARES_EBADNAME; + + *s = malloc(nlen.uns + 1); + if (!*s) + return ARES_ENOMEM; + q = *s; + + if (nlen.uns == 0) { + /* RFC2181 says this should be ".": the root of the DNS tree. + * Since this function strips trailing dots though, it becomes "" + */ + q[0] = '\0'; + *enclen = 1; /* the caller should move one byte to get past this */ + return ARES_SUCCESS; + } + + /* No error-checking necessary; it was all done by name_length(). */ + p = encoded; + while (*p) + { + if ((*p & INDIR_MASK) == INDIR_MASK) + { + if (!indir) + { + *enclen = p + 2 - encoded; + indir = 1; + } + p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1)); + } + else + { + len = *p; + p++; + while (len--) + { + if (*p == '.' || *p == '\\') + *q++ = '\\'; + *q++ = *p; + p++; + } + *q++ = '.'; + } + } + if (!indir) + *enclen = p + 1 - encoded; + + /* Nuke the trailing period if we wrote one. */ + if (q > *s) + *(q - 1) = 0; + else + *q = 0; /* zero terminate */ + + return ARES_SUCCESS; +} + +/* Return the length of the expansion of an encoded domain name, or + * -1 if the encoding is invalid. + */ +static int name_length(const unsigned char *encoded, const unsigned char *abuf, + int alen) +{ + int n = 0, offset, indir = 0; + + /* Allow the caller to pass us abuf + alen and have us check for it. */ + if (encoded == abuf + alen) + return -1; + + while (*encoded) + { + if ((*encoded & INDIR_MASK) == INDIR_MASK) + { + /* Check the offset and go there. */ + if (encoded + 1 >= abuf + alen) + return -1; + offset = (*encoded & ~INDIR_MASK) << 8 | *(encoded + 1); + if (offset >= alen) + return -1; + encoded = abuf + offset; + + /* If we've seen more indirects than the message length, + * then there's a loop. + */ + if (++indir > alen) + return -1; + } + else + { + offset = *encoded; + if (encoded + offset + 1 >= abuf + alen) + return -1; + encoded++; + while (offset--) + { + n += (*encoded == '.' || *encoded == '\\') ? 2 : 1; + encoded++; + } + n++; + } + } + + /* If there were any labels at all, then the number of dots is one + * less than the number of labels, so subtract one. + */ + return (n) ? n - 1 : n; +} + +/* Like ares_expand_name but returns EBADRESP in case of invalid input. */ +int ares__expand_name_for_response(const unsigned char *encoded, + const unsigned char *abuf, int alen, + char **s, long *enclen) +{ + int status = ares_expand_name(encoded, abuf, alen, s, enclen); + if (status == ARES_EBADNAME) + status = ARES_EBADRESP; + return status; +} diff --git a/deps/c-ares/ares_expand_string.c b/deps/c-ares/ares_expand_string.c new file mode 100644 index 00000000000..3b7b34138eb --- /dev/null +++ b/deps/c-ares/ares_expand_string.c @@ -0,0 +1,76 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif + +#include +#include +#include "ares.h" +#include "ares_private.h" /* for the memdebug */ + +/* Simply decodes a length-encoded character string. The first byte of the + * input is the length of the string to be returned and the bytes thereafter + * are the characters of the string. The returned result will be NULL + * terminated. + */ +int ares_expand_string(const unsigned char *encoded, + const unsigned char *abuf, + int alen, + unsigned char **s, + long *enclen) +{ + unsigned char *q; + union { + ssize_t sig; + size_t uns; + } elen; + + if (encoded == abuf+alen) + return ARES_EBADSTR; + + elen.uns = *encoded; + if (encoded+elen.sig+1 > abuf+alen) + return ARES_EBADSTR; + + encoded++; + + *s = malloc(elen.uns+1); + if (*s == NULL) + return ARES_ENOMEM; + q = *s; + strncpy((char *)q, (char *)encoded, elen.uns); + q[elen.uns] = '\0'; + + *s = q; + + *enclen = (long)(elen.sig+1); + + return ARES_SUCCESS; +} + diff --git a/deps/c-ares/ares_fds.c b/deps/c-ares/ares_fds.c new file mode 100644 index 00000000000..bbf5c454ab5 --- /dev/null +++ b/deps/c-ares/ares_fds.c @@ -0,0 +1,63 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "ares.h" +#include "ares_private.h" + +int ares_fds(ares_channel channel, fd_set *read_fds, fd_set *write_fds) +{ + struct server_state *server; + ares_socket_t nfds; + int i; + + /* Are there any active queries? */ + int active_queries = !ares__is_list_empty(&(channel->all_queries)); + + nfds = 0; + for (i = 0; i < channel->nservers; i++) + { + server = &channel->servers[i]; + /* We only need to register interest in UDP sockets if we have + * outstanding queries. + */ + if (active_queries && server->udp_socket != ARES_SOCKET_BAD) + { + FD_SET(server->udp_socket, read_fds); + if (server->udp_socket >= nfds) + nfds = server->udp_socket + 1; + } + /* We always register for TCP events, because we want to know + * when the other side closes the connection, so we don't waste + * time trying to use a broken connection. + */ + if (server->tcp_socket != ARES_SOCKET_BAD) + { + FD_SET(server->tcp_socket, read_fds); + if (server->qhead) + FD_SET(server->tcp_socket, write_fds); + if (server->tcp_socket >= nfds) + nfds = server->tcp_socket + 1; + } + } + return (int)nfds; +} diff --git a/deps/c-ares/ares_free_hostent.c b/deps/c-ares/ares_free_hostent.c new file mode 100644 index 00000000000..f07fd7c15ba --- /dev/null +++ b/deps/c-ares/ares_free_hostent.c @@ -0,0 +1,40 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include + +#ifdef HAVE_NETDB_H +#include +#endif + +#include "ares.h" +#include "ares_private.h" /* for memdebug */ + +void ares_free_hostent(struct hostent *host) +{ + char **p; + + free((char *)(host->h_name)); + for (p = host->h_aliases; *p; p++) + free(*p); + free(host->h_aliases); + free(host->h_addr_list[0]); /* no matter if there is one or many entries, + there is only one malloc for all of them */ + free(host->h_addr_list); + free(host); +} diff --git a/deps/c-ares/ares_free_string.c b/deps/c-ares/ares_free_string.c new file mode 100644 index 00000000000..dc27f5b340d --- /dev/null +++ b/deps/c-ares/ares_free_string.c @@ -0,0 +1,26 @@ +/* $Id$ */ + +/* Copyright 2000 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include +#include "ares.h" +#include "ares_private.h" + +void ares_free_string(void *str) +{ + free(str); +} diff --git a/deps/c-ares/ares_gethostbyaddr.c b/deps/c-ares/ares_gethostbyaddr.c new file mode 100644 index 00000000000..a2c3a90769f --- /dev/null +++ b/deps/c-ares/ares_gethostbyaddr.c @@ -0,0 +1,291 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include + +#include "ares.h" +#include "inet_net_pton.h" +#include "ares_private.h" + +#ifdef WATT32 +#undef WIN32 +#endif + +struct addr_query { + /* Arguments passed to ares_gethostbyaddr() */ + ares_channel channel; + struct ares_addr addr; + ares_host_callback callback; + void *arg; + + const char *remaining_lookups; + int timeouts; +}; + +static void next_lookup(struct addr_query *aquery); +static void addr_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen); +static void end_aquery(struct addr_query *aquery, int status, + struct hostent *host); +static int file_lookup(struct ares_addr *addr, struct hostent **host); +static void ptr_rr_name(char *name, const struct ares_addr *addr); + +void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen, + int family, ares_host_callback callback, void *arg) +{ + struct addr_query *aquery; + + if (family != AF_INET && family != AF_INET6) + { + callback(arg, ARES_ENOTIMP, 0, NULL); + return; + } + + if ((family == AF_INET && addrlen != sizeof(aquery->addr.addrV4)) || + (family == AF_INET6 && addrlen != sizeof(aquery->addr.addrV6))) + { + callback(arg, ARES_ENOTIMP, 0, NULL); + return; + } + + aquery = malloc(sizeof(struct addr_query)); + if (!aquery) + { + callback(arg, ARES_ENOMEM, 0, NULL); + return; + } + aquery->channel = channel; + if (family == AF_INET) + memcpy(&aquery->addr.addrV4, addr, sizeof(aquery->addr.addrV4)); + else + memcpy(&aquery->addr.addrV6, addr, sizeof(aquery->addr.addrV6)); + aquery->addr.family = family; + aquery->callback = callback; + aquery->arg = arg; + aquery->remaining_lookups = channel->lookups; + aquery->timeouts = 0; + + next_lookup(aquery); +} + +static void next_lookup(struct addr_query *aquery) +{ + const char *p; + char name[128]; + int status; + struct hostent *host; + + for (p = aquery->remaining_lookups; *p; p++) + { + switch (*p) + { + case 'b': + ptr_rr_name(name, &aquery->addr); + aquery->remaining_lookups = p + 1; + ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback, + aquery); + return; + case 'f': + status = file_lookup(&aquery->addr, &host); + + /* this status check below previously checked for !ARES_ENOTFOUND, + but we should not assume that this single error code is the one + that can occur, as that is in fact no longer the case */ + if (status == ARES_SUCCESS) + { + end_aquery(aquery, status, host); + return; + } + break; + } + } + end_aquery(aquery, ARES_ENOTFOUND, NULL); +} + +static void addr_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen) +{ + struct addr_query *aquery = (struct addr_query *) arg; + struct hostent *host; + size_t addrlen; + + aquery->timeouts += timeouts; + if (status == ARES_SUCCESS) + { + if (aquery->addr.family == AF_INET) + { + addrlen = sizeof(aquery->addr.addrV4); + status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV4, + (int)addrlen, AF_INET, &host); + } + else + { + addrlen = sizeof(aquery->addr.addrV6); + status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV6, + (int)addrlen, AF_INET6, &host); + } + end_aquery(aquery, status, host); + } + else if (status == ARES_EDESTRUCTION) + end_aquery(aquery, status, NULL); + else + next_lookup(aquery); +} + +static void end_aquery(struct addr_query *aquery, int status, + struct hostent *host) +{ + aquery->callback(aquery->arg, status, aquery->timeouts, host); + if (host) + ares_free_hostent(host); + free(aquery); +} + +static int file_lookup(struct ares_addr *addr, struct hostent **host) +{ + FILE *fp; + int status; + int error; + +#ifdef WIN32 + char PATH_HOSTS[MAX_PATH]; + if (IS_NT()) { + char tmp[MAX_PATH]; + HKEY hkeyHosts; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hkeyHosts) + == ERROR_SUCCESS) + { + DWORD dwLength = MAX_PATH; + RegQueryValueEx(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp, + &dwLength); + ExpandEnvironmentStrings(tmp, PATH_HOSTS, MAX_PATH); + RegCloseKey(hkeyHosts); + } + } + else + GetWindowsDirectory(PATH_HOSTS, MAX_PATH); + + strcat(PATH_HOSTS, WIN_PATH_HOSTS); + +#elif defined(WATT32) + extern const char *_w32_GetHostsFile (void); + const char *PATH_HOSTS = _w32_GetHostsFile(); + + if (!PATH_HOSTS) + return ARES_ENOTFOUND; +#endif + + fp = fopen(PATH_HOSTS, "r"); + if (!fp) + { + error = ERRNO; + switch(error) + { + case ENOENT: + case ESRCH: + return ARES_ENOTFOUND; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", + PATH_HOSTS)); + *host = NULL; + return ARES_EFILE; + } + } + while ((status = ares__get_hostent(fp, addr->family, host)) == ARES_SUCCESS) + { + if (addr->family != (*host)->h_addrtype) + { + ares_free_hostent(*host); + continue; + } + if (addr->family == AF_INET) + { + if (memcmp((*host)->h_addr, &addr->addrV4, sizeof(addr->addrV4)) == 0) + break; + } + else if (addr->family == AF_INET6) + { + if (memcmp((*host)->h_addr, &addr->addrV6, sizeof(addr->addrV6)) == 0) + break; + } + ares_free_hostent(*host); + } + fclose(fp); + if (status == ARES_EOF) + status = ARES_ENOTFOUND; + if (status != ARES_SUCCESS) + *host = NULL; + return status; +} + +static void ptr_rr_name(char *name, const struct ares_addr *addr) +{ + if (addr->family == AF_INET) + { + unsigned long laddr = ntohl(addr->addrV4.s_addr); + int a1 = (int)((laddr >> 24) & 0xff); + int a2 = (int)((laddr >> 16) & 0xff); + int a3 = (int)((laddr >> 8) & 0xff); + int a4 = (int)(laddr & 0xff); + sprintf(name, "%d.%d.%d.%d.in-addr.arpa", a4, a3, a2, a1); + } + else + { + unsigned char *bytes = (unsigned char *)&addr->addrV6; + /* There are too many arguments to do this in one line using + * minimally C89-compliant compilers */ + sprintf(name, + "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.", + bytes[15]&0xf, bytes[15] >> 4, bytes[14]&0xf, bytes[14] >> 4, + bytes[13]&0xf, bytes[13] >> 4, bytes[12]&0xf, bytes[12] >> 4, + bytes[11]&0xf, bytes[11] >> 4, bytes[10]&0xf, bytes[10] >> 4, + bytes[9]&0xf, bytes[9] >> 4, bytes[8]&0xf, bytes[8] >> 4); + sprintf(name+strlen(name), + "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa", + bytes[7]&0xf, bytes[7] >> 4, bytes[6]&0xf, bytes[6] >> 4, + bytes[5]&0xf, bytes[5] >> 4, bytes[4]&0xf, bytes[4] >> 4, + bytes[3]&0xf, bytes[3] >> 4, bytes[2]&0xf, bytes[2] >> 4, + bytes[1]&0xf, bytes[1] >> 4, bytes[0]&0xf, bytes[0] >> 4); + } +} diff --git a/deps/c-ares/ares_gethostbyname.c b/deps/c-ares/ares_gethostbyname.c new file mode 100644 index 00000000000..ebad6707510 --- /dev/null +++ b/deps/c-ares/ares_gethostbyname.c @@ -0,0 +1,513 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#include "ares.h" +#include "inet_net_pton.h" +#include "bitncmp.h" +#include "ares_private.h" + +#ifdef WATT32 +#undef WIN32 +#endif + +struct host_query { + /* Arguments passed to ares_gethostbyname() */ + ares_channel channel; + char *name; + ares_host_callback callback; + void *arg; + int sent_family; /* this family is what was is being used */ + int want_family; /* this family is what is asked for in the API */ + const char *remaining_lookups; + int timeouts; +}; + +static void next_lookup(struct host_query *hquery, int status_code); +static void host_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen); +static void end_hquery(struct host_query *hquery, int status, + struct hostent *host); +static int fake_hostent(const char *name, int family, + ares_host_callback callback, void *arg); +static int file_lookup(const char *name, int family, struct hostent **host); +static void sort_addresses(struct hostent *host, + const struct apattern *sortlist, int nsort); +static void sort6_addresses(struct hostent *host, + const struct apattern *sortlist, int nsort); +static int get_address_index(const struct in_addr *addr, + const struct apattern *sortlist, int nsort); +static int get6_address_index(const struct ares_in6_addr *addr, + const struct apattern *sortlist, int nsort); + +void ares_gethostbyname(ares_channel channel, const char *name, int family, + ares_host_callback callback, void *arg) +{ + struct host_query *hquery; + + /* Right now we only know how to look up Internet addresses - and unspec + means try both basically. */ + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + callback(arg, ARES_ENOTIMP, 0, NULL); + return; + } + + if (fake_hostent(name, family, callback, arg)) + return; + + /* Allocate and fill in the host query structure. */ + hquery = malloc(sizeof(struct host_query)); + if (!hquery) + { + callback(arg, ARES_ENOMEM, 0, NULL); + return; + } + hquery->channel = channel; + hquery->name = strdup(name); + hquery->want_family = family; + hquery->sent_family = -1; /* nothing is sent yet */ + if (!hquery->name) { + free(hquery); + callback(arg, ARES_ENOMEM, 0, NULL); + return; + } + hquery->callback = callback; + hquery->arg = arg; + hquery->remaining_lookups = channel->lookups; + hquery->timeouts = 0; + + /* Start performing lookups according to channel->lookups. */ + next_lookup(hquery, ARES_ECONNREFUSED /* initial error code */); +} + +static void next_lookup(struct host_query *hquery, int status_code) +{ + const char *p; + struct hostent *host; + int status = status_code; + + for (p = hquery->remaining_lookups; *p; p++) + { + switch (*p) + { + case 'b': + /* DNS lookup */ + hquery->remaining_lookups = p + 1; + if ((hquery->want_family == AF_INET6) || + (hquery->want_family == AF_UNSPEC)) { + /* if inet6 or unspec, start out with AAAA */ + hquery->sent_family = AF_INET6; + ares_search(hquery->channel, hquery->name, C_IN, T_AAAA, + host_callback, hquery); + } + else { + hquery->sent_family = AF_INET; + ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback, + hquery); + } + return; + + case 'f': + /* Host file lookup */ + status = file_lookup(hquery->name, hquery->want_family, &host); + + /* this status check below previously checked for !ARES_ENOTFOUND, + but we should not assume that this single error code is the one + that can occur, as that is in fact no longer the case */ + if (status == ARES_SUCCESS) + { + end_hquery(hquery, status, host); + return; + } + status = status_code; /* Use original status code */ + break; + } + } + end_hquery(hquery, status, NULL); +} + +static void host_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen) +{ + struct host_query *hquery = (struct host_query *) arg; + ares_channel channel = hquery->channel; + struct hostent *host = NULL; + + hquery->timeouts += timeouts; + if (status == ARES_SUCCESS) + { + if (hquery->sent_family == AF_INET) + { + status = ares_parse_a_reply(abuf, alen, &host, NULL, NULL); + if (host && channel->nsort) + sort_addresses(host, channel->sortlist, channel->nsort); + } + else if (hquery->sent_family == AF_INET6) + { + status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL); + if (status == ARES_ENODATA || status == ARES_EBADRESP) { + /* The query returned something but either there were no AAAA records (e.g. just CNAME) + or the response was malformed. Try looking up A instead. + We should possibly limit this attempt-next logic to AF_UNSPEC lookups only. */ + hquery->sent_family = AF_INET; + ares_search(hquery->channel, hquery->name, C_IN, T_A, + host_callback, hquery); + return; + } + if (host && channel->nsort) + sort6_addresses(host, channel->sortlist, channel->nsort); + } + end_hquery(hquery, status, host); + } + else if ((status == ARES_ENODATA || status == ARES_EBADRESP || status == ARES_ETIMEOUT) && hquery->sent_family == AF_INET6) + { + /* The AAAA query yielded no useful result. Now look up an A instead. + We should possibly limit this attempt-next logic to AF_UNSPEC lookups only. */ + hquery->sent_family = AF_INET; + ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback, + hquery); + } + else if (status == ARES_EDESTRUCTION) + end_hquery(hquery, status, NULL); + else + next_lookup(hquery, status); +} + +static void end_hquery(struct host_query *hquery, int status, + struct hostent *host) +{ + hquery->callback(hquery->arg, status, hquery->timeouts, host); + if (host) + ares_free_hostent(host); + free(hquery->name); + free(hquery); +} + +/* If the name looks like an IP address, fake up a host entry, end the + * query immediately, and return true. Otherwise return false. + */ +static int fake_hostent(const char *name, int family, ares_host_callback callback, + void *arg) +{ + struct hostent hostent; + char *aliases[1] = { NULL }; + char *addrs[2]; + int result = 0; + struct in_addr in; + struct ares_in6_addr in6; + + if (family == AF_INET || family == AF_INET6) + { + /* It only looks like an IP address if it's all numbers and dots. */ + int numdots = 0, valid = 1; + const char *p; + for (p = name; *p; p++) + { + if (!ISDIGIT(*p) && *p != '.') { + valid = 0; + break; + } else if (*p == '.') { + numdots++; + } + } + + /* if we don't have 3 dots, it is illegal + * (although inet_addr doesn't think so). + */ + if (numdots != 3 || !valid) + result = 0; + else + result = ((in.s_addr = inet_addr(name)) == INADDR_NONE ? 0 : 1); + + if (result) + family = AF_INET; + } + if (family == AF_INET6) + result = (ares_inet_pton(AF_INET6, name, &in6) < 1 ? 0 : 1); + + if (!result) + return 0; + + if (family == AF_INET) + { + hostent.h_length = (int)sizeof(struct in_addr); + addrs[0] = (char *)∈ + } + else if (family == AF_INET6) + { + hostent.h_length = (int)sizeof(struct ares_in6_addr); + addrs[0] = (char *)&in6; + } + /* Duplicate the name, to avoid a constness violation. */ + hostent.h_name = strdup(name); + if (!hostent.h_name) + { + callback(arg, ARES_ENOMEM, 0, NULL); + return 1; + } + + /* Fill in the rest of the host structure and terminate the query. */ + addrs[1] = NULL; + hostent.h_aliases = aliases; + hostent.h_addrtype = family; + hostent.h_addr_list = addrs; + callback(arg, ARES_SUCCESS, 0, &hostent); + + free((char *)(hostent.h_name)); + return 1; +} + +/* This is an API method */ +int ares_gethostbyname_file(ares_channel channel, const char *name, + int family, struct hostent **host) +{ + int result; + + /* We only take the channel to ensure that ares_init() been called. */ + if(channel == NULL) + { + /* Anything will do, really. This seems fine, and is consistent with + other error cases. */ + *host = NULL; + return ARES_ENOTFOUND; + } + + /* Just chain to the internal implementation we use here; it's exactly + * what we want. + */ + result = file_lookup(name, family, host); + if(result != ARES_SUCCESS) + { + /* We guarantee a NULL hostent on failure. */ + *host = NULL; + } + return result; +} + +static int file_lookup(const char *name, int family, struct hostent **host) +{ + FILE *fp; + char **alias; + int status; + int error; + +#ifdef WIN32 + char PATH_HOSTS[MAX_PATH]; + if (IS_NT()) { + char tmp[MAX_PATH]; + HKEY hkeyHosts; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hkeyHosts) + == ERROR_SUCCESS) + { + DWORD dwLength = MAX_PATH; + RegQueryValueEx(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp, + &dwLength); + ExpandEnvironmentStrings(tmp, PATH_HOSTS, MAX_PATH); + RegCloseKey(hkeyHosts); + } + } + else + GetWindowsDirectory(PATH_HOSTS, MAX_PATH); + + strcat(PATH_HOSTS, WIN_PATH_HOSTS); + +#elif defined(WATT32) + extern const char *_w32_GetHostsFile (void); + const char *PATH_HOSTS = _w32_GetHostsFile(); + + if (!PATH_HOSTS) + return ARES_ENOTFOUND; +#endif + + fp = fopen(PATH_HOSTS, "r"); + if (!fp) + { + error = ERRNO; + switch(error) + { + case ENOENT: + case ESRCH: + return ARES_ENOTFOUND; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", + PATH_HOSTS)); + *host = NULL; + return ARES_EFILE; + } + } + while ((status = ares__get_hostent(fp, family, host)) == ARES_SUCCESS) + { + if (strcasecmp((*host)->h_name, name) == 0) + break; + for (alias = (*host)->h_aliases; *alias; alias++) + { + if (strcasecmp(*alias, name) == 0) + break; + } + if (*alias) + break; + ares_free_hostent(*host); + } + fclose(fp); + if (status == ARES_EOF) + status = ARES_ENOTFOUND; + if (status != ARES_SUCCESS) + *host = NULL; + return status; +} + +static void sort_addresses(struct hostent *host, const struct apattern *sortlist, + int nsort) +{ + struct in_addr a1, a2; + int i1, i2, ind1, ind2; + + /* This is a simple insertion sort, not optimized at all. i1 walks + * through the address list, with the loop invariant that everything + * to the left of i1 is sorted. In the loop body, the value at i1 is moved + * back through the list (via i2) until it is in sorted order. + */ + for (i1 = 0; host->h_addr_list[i1]; i1++) + { + memcpy(&a1, host->h_addr_list[i1], sizeof(struct in_addr)); + ind1 = get_address_index(&a1, sortlist, nsort); + for (i2 = i1 - 1; i2 >= 0; i2--) + { + memcpy(&a2, host->h_addr_list[i2], sizeof(struct in_addr)); + ind2 = get_address_index(&a2, sortlist, nsort); + if (ind2 <= ind1) + break; + memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in_addr)); + } + memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in_addr)); + } +} + +/* Find the first entry in sortlist which matches addr. Return nsort + * if none of them match. + */ +static int get_address_index(const struct in_addr *addr, + const struct apattern *sortlist, + int nsort) +{ + int i; + + for (i = 0; i < nsort; i++) + { + if (sortlist[i].family != AF_INET) + continue; + if (sortlist[i].type == PATTERN_MASK) + { + if ((addr->s_addr & sortlist[i].mask.addr4.s_addr) + == sortlist[i].addrV4.s_addr) + break; + } + else + { + if (!ares_bitncmp(&addr->s_addr, &sortlist[i].addrV4.s_addr, + sortlist[i].mask.bits)) + break; + } + } + return i; +} + +static void sort6_addresses(struct hostent *host, const struct apattern *sortlist, + int nsort) +{ + struct ares_in6_addr a1, a2; + int i1, i2, ind1, ind2; + + /* This is a simple insertion sort, not optimized at all. i1 walks + * through the address list, with the loop invariant that everything + * to the left of i1 is sorted. In the loop body, the value at i1 is moved + * back through the list (via i2) until it is in sorted order. + */ + for (i1 = 0; host->h_addr_list[i1]; i1++) + { + memcpy(&a1, host->h_addr_list[i1], sizeof(struct ares_in6_addr)); + ind1 = get6_address_index(&a1, sortlist, nsort); + for (i2 = i1 - 1; i2 >= 0; i2--) + { + memcpy(&a2, host->h_addr_list[i2], sizeof(struct ares_in6_addr)); + ind2 = get6_address_index(&a2, sortlist, nsort); + if (ind2 <= ind1) + break; + memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct ares_in6_addr)); + } + memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct ares_in6_addr)); + } +} + +/* Find the first entry in sortlist which matches addr. Return nsort + * if none of them match. + */ +static int get6_address_index(const struct ares_in6_addr *addr, + const struct apattern *sortlist, + int nsort) +{ + int i; + + for (i = 0; i < nsort; i++) + { + if (sortlist[i].family != AF_INET6) + continue; + if (!ares_bitncmp(addr, + &sortlist[i].addrV6, + sortlist[i].mask.bits)) + break; + } + return i; +} diff --git a/deps/c-ares/ares_getnameinfo.c b/deps/c-ares/ares_getnameinfo.c new file mode 100644 index 00000000000..77752df0258 --- /dev/null +++ b/deps/c-ares/ares_getnameinfo.c @@ -0,0 +1,413 @@ +/* $Id$ */ + +/* Copyright 2005 by Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ +#include "ares_setup.h" + +#ifdef HAVE_GETSERVBYPORT_R +# if !defined(GETSERVBYPORT_R_ARGS) || \ + (GETSERVBYPORT_R_ARGS < 4) || (GETSERVBYPORT_R_ARGS > 6) +# error "you MUST specifiy a valid number of arguments for getservbyport_r" +# endif +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_NET_IF_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include + +#include "ares.h" +#include "ares_ipv6.h" +#include "inet_ntop.h" +#include "ares_private.h" + +struct nameinfo_query { + ares_nameinfo_callback callback; + void *arg; + union { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + } addr; + int family; + int flags; + int timeouts; +}; + +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID +#define IPBUFSIZ \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + IF_NAMESIZE) +#else +#define IPBUFSIZ \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")) +#endif + +static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host); +static char *lookup_service(unsigned short port, int flags, + char *buf, size_t buflen); +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID +static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid, + char *buf, size_t buflen); +#endif +static char *ares_striendstr(const char *s1, const char *s2); + +void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, + ares_socklen_t salen, + int flags, ares_nameinfo_callback callback, void *arg) +{ + struct sockaddr_in *addr = NULL; + struct sockaddr_in6 *addr6 = NULL; + struct nameinfo_query *niquery; + unsigned int port = 0; + + /* Verify the buffer size */ + if (salen == sizeof(struct sockaddr_in)) + { + addr = (struct sockaddr_in *)sa; + port = addr->sin_port; + } + else if (salen == sizeof(struct sockaddr_in6)) + { + addr6 = (struct sockaddr_in6 *)sa; + port = addr6->sin6_port; + } + else + { + callback(arg, ARES_ENOTIMP, 0, NULL, NULL); + return; + } + + /* If neither, assume they want a host */ + if (!(flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST)) + flags |= ARES_NI_LOOKUPHOST; + + /* All they want is a service, no need for DNS */ + if ((flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST)) + { + char buf[33], *service; + + service = lookup_service((unsigned short)(port & 0xffff), + flags, buf, sizeof(buf)); + callback(arg, ARES_SUCCESS, 0, NULL, service); + return; + } + + /* They want a host lookup */ + if ((flags & ARES_NI_LOOKUPHOST)) + { + /* A numeric host can be handled without DNS */ + if ((flags & ARES_NI_NUMERICHOST)) + { + char ipbuf[IPBUFSIZ]; + char srvbuf[33]; + char *service = NULL; + ipbuf[0] = 0; + + /* Specifying not to lookup a host, but then saying a host + * is required has to be illegal. + */ + if (flags & ARES_NI_NAMEREQD) + { + callback(arg, ARES_EBADFLAGS, 0, NULL, NULL); + return; + } + if (salen == sizeof(struct sockaddr_in6)) + { + ares_inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, IPBUFSIZ); + /* If the system supports scope IDs, use it */ +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + append_scopeid(addr6, flags, ipbuf, sizeof(ipbuf)); +#endif + } + else + { + ares_inet_ntop(AF_INET, &addr->sin_addr, ipbuf, IPBUFSIZ); + } + /* They also want a service */ + if (flags & ARES_NI_LOOKUPSERVICE) + service = lookup_service((unsigned short)(port & 0xffff), + flags, srvbuf, sizeof(srvbuf)); + callback(arg, ARES_SUCCESS, 0, ipbuf, service); + return; + } + /* This is where a DNS lookup becomes necessary */ + else + { + niquery = malloc(sizeof(struct nameinfo_query)); + if (!niquery) + { + callback(arg, ARES_ENOMEM, 0, NULL, NULL); + return; + } + niquery->callback = callback; + niquery->arg = arg; + niquery->flags = flags; + niquery->timeouts = 0; + if (sa->sa_family == AF_INET) + { + niquery->family = AF_INET; + memcpy(&niquery->addr.addr4, addr, sizeof(addr)); + ares_gethostbyaddr(channel, &addr->sin_addr, + sizeof(struct in_addr), AF_INET, + nameinfo_callback, niquery); + } + else + { + niquery->family = AF_INET6; + memcpy(&niquery->addr.addr6, addr6, sizeof(addr6)); + ares_gethostbyaddr(channel, &addr6->sin6_addr, + sizeof(struct ares_in6_addr), AF_INET6, + nameinfo_callback, niquery); + } + } + } +} + +static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host) +{ + struct nameinfo_query *niquery = (struct nameinfo_query *) arg; + char srvbuf[33]; + char *service = NULL; + + niquery->timeouts += timeouts; + if (status == ARES_SUCCESS) + { + /* They want a service too */ + if (niquery->flags & ARES_NI_LOOKUPSERVICE) + { + if (niquery->family == AF_INET) + service = lookup_service(niquery->addr.addr4.sin_port, + niquery->flags, srvbuf, sizeof(srvbuf)); + else + service = lookup_service(niquery->addr.addr6.sin6_port, + niquery->flags, srvbuf, sizeof(srvbuf)); + } + /* NOFQDN means we have to strip off the domain name portion. + We do this by determining our own domain name, then searching the string + for this domain name and removing it. + */ +#ifdef HAVE_GETHOSTNAME + if (niquery->flags & ARES_NI_NOFQDN) + { + char buf[255]; + char *domain; + gethostname(buf, 255); + if ((domain = strchr(buf, '.'))) + { + char *end = ares_striendstr(host->h_name, domain); + if (end) + *end = 0; + } + } +#endif + niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, (char *)(host->h_name), + service); + return; + } + /* We couldn't find the host, but it's OK, we can use the IP */ + else if (status == ARES_ENOTFOUND && !(niquery->flags & ARES_NI_NAMEREQD)) + { + char ipbuf[IPBUFSIZ]; + if (niquery->family == AF_INET) + ares_inet_ntop(AF_INET, &niquery->addr.addr4.sin_addr, ipbuf, IPBUFSIZ); + else + { + ares_inet_ntop(AF_INET6, &niquery->addr.addr6.sin6_addr, ipbuf, IPBUFSIZ); +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + append_scopeid(&niquery->addr.addr6, niquery->flags, ipbuf, sizeof(ipbuf)); +#endif + } + /* They want a service too */ + if (niquery->flags & ARES_NI_LOOKUPSERVICE) + { + if (niquery->family == AF_INET) + service = lookup_service(niquery->addr.addr4.sin_port, + niquery->flags, srvbuf, sizeof(srvbuf)); + else + service = lookup_service(niquery->addr.addr6.sin6_port, + niquery->flags, srvbuf, sizeof(srvbuf)); + } + niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, ipbuf, service); + return; + } + niquery->callback(niquery->arg, status, niquery->timeouts, NULL, NULL); + free(niquery); +} + +static char *lookup_service(unsigned short port, int flags, + char *buf, size_t buflen) +{ + const char *proto; + struct servent *sep; +#ifdef HAVE_GETSERVBYPORT_R + struct servent se; +#endif + char tmpbuf[4096]; + + if (port) + { + if (flags & ARES_NI_NUMERICSERV) + sep = NULL; + else + { + if (flags & ARES_NI_UDP) + proto = "udp"; + else if (flags & ARES_NI_SCTP) + proto = "sctp"; + else if (flags & ARES_NI_DCCP) + proto = "dccp"; + else + proto = "tcp"; +#ifdef HAVE_GETSERVBYPORT_R + sep = &se; + memset(tmpbuf, 0, sizeof(tmpbuf)); +#if GETSERVBYPORT_R_ARGS == 6 + if (getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf), &sep) != 0) + sep = NULL; +#elif GETSERVBYPORT_R_ARGS == 5 + sep = getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf)); +#elif GETSERVBYPORT_R_ARGS == 4 + if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0) + sep = NULL; +#else + /* Lets just hope the OS uses TLS! */ + sep = getservbyport(port, proto); +#endif +#else + /* Lets just hope the OS uses TLS! */ +#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) + sep = getservbyport(port, (char*)proto); +#else + sep = getservbyport(port, proto); +#endif +#endif + } + if (sep && sep->s_name) + /* get service name */ + strcpy(tmpbuf, sep->s_name); + else + /* get port as a string */ + sprintf(tmpbuf, "%u", (unsigned int)ntohs(port)); + if (strlen(tmpbuf) < buflen) + /* return it if buffer big enough */ + strcpy(buf, tmpbuf); + else + /* avoid reusing previous one */ + buf[0] = '\0'; + return buf; + } + buf[0] = '\0'; + return NULL; +} + +#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID +static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags, + char *buf, size_t buflen) +{ +#ifdef HAVE_IF_INDEXTONAME + int is_ll, is_mcll; +#endif + char fmt_u[] = "%u"; + char fmt_lu[] = "%lu"; + char tmpbuf[IF_NAMESIZE + 2]; + size_t bufl; + char *fmt = (sizeof(addr6->sin6_scope_id) > sizeof(unsigned int))?fmt_lu:fmt_u; + + tmpbuf[0] = '%'; + +#ifdef HAVE_IF_INDEXTONAME + is_ll = IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr); + is_mcll = IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr); + if ((flags & ARES_NI_NUMERICSCOPE) || + (!is_ll && !is_mcll)) + { + sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id); + } + else + { + if (if_indextoname(addr6->sin6_scope_id, &tmpbuf[1]) == NULL) + sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id); + } +#else + sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id); + (void) flags; +#endif + tmpbuf[IF_NAMESIZE + 1] = '\0'; + bufl = strlen(buf); + + if(bufl + strlen(tmpbuf) < buflen) + /* only append the scopeid string if it fits in the target buffer */ + strcpy(&buf[bufl], tmpbuf); +} +#endif + +/* Determines if s1 ends with the string in s2 (case-insensitive) */ +static char *ares_striendstr(const char *s1, const char *s2) +{ + const char *c1, *c2, *c1_begin; + int lo1, lo2; + size_t s1_len = strlen(s1), s2_len = strlen(s2); + + /* If the substr is longer than the full str, it can't match */ + if (s2_len > s1_len) + return NULL; + + /* Jump to the end of s1 minus the length of s2 */ + c1_begin = s1+s1_len-s2_len; + c1 = (const char *)c1_begin; + c2 = s2; + while (c2 < s2+s2_len) + { + lo1 = tolower(*c1); + lo2 = tolower(*c2); + if (lo1 != lo2) + return NULL; + else + { + c1++; + c2++; + } + } + if (c2 == c1 && c2 == NULL) + return (char *)c1_begin; + return NULL; +} diff --git a/deps/c-ares/ares_getopt.c b/deps/c-ares/ares_getopt.c new file mode 100644 index 00000000000..b3cbb012d1d --- /dev/null +++ b/deps/c-ares/ares_getopt.c @@ -0,0 +1,123 @@ +/* + * Original file name getopt.c Initial import into the c-ares source tree + * on 2007-04-11. Lifted from version 5.2 of the 'Open Mash' project with + * the modified BSD license, BSD license without the advertising clause. + * + * $Id$ + */ + +/* + * getopt.c -- + * + * Standard UNIX getopt function. Code is from BSD. + * + * Copyright (c) 1987-2001 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * A. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * B. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * C. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* #if !defined(lint) + * static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; + * #endif + */ + +#include +#include +#include +#include "ares_getopt.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1; /* index into parent argv vector */ +int optopt = 0; /* character checked for validity */ +static int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG (char *)"" + +/* + * ares_getopt -- + * Parse argc/argv argument vector. + */ +int +ares_getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + (oli = strchr(ostr, optopt)) == NULL) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return (EOF); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __FILE__, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __FILE__, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/deps/c-ares/ares_getopt.h b/deps/c-ares/ares_getopt.h new file mode 100644 index 00000000000..63acb3b4232 --- /dev/null +++ b/deps/c-ares/ares_getopt.h @@ -0,0 +1,53 @@ +#ifndef ARES_GETOPT_H +#define ARES_GETOPT_H + +/* + * Copyright (c) 1987-2001 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * A. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * B. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * C. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +int ares_getopt(int nargc, char * const nargv[], const char *ostr); + +#undef optarg +#undef optind +#undef opterr +#undef optopt +#undef optreset + +#define optarg ares_optarg +#define optind ares_optind +#define opterr ares_opterr +#define optopt ares_optopt +#define optreset ares_optreset + +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +#endif /* ARES_GETOPT_H */ diff --git a/deps/c-ares/ares_getsock.c b/deps/c-ares/ares_getsock.c new file mode 100644 index 00000000000..52aaecd0bca --- /dev/null +++ b/deps/c-ares/ares_getsock.c @@ -0,0 +1,73 @@ +/* $Id$ */ + +/* Copyright (C) 2005 - 2010, Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "ares.h" +#include "ares_private.h" + +int ares_getsock(ares_channel channel, + ares_socket_t *socks, + int numsocks) /* size of the 'socks' array */ +{ + struct server_state *server; + int i; + int sockindex=0; + int bitmap = 0; + unsigned int setbits = 0xffffffff; + + /* Are there any active queries? */ + int active_queries = !ares__is_list_empty(&(channel->all_queries)); + + for (i = 0; + (i < channel->nservers) && (sockindex < ARES_GETSOCK_MAXNUM); + i++) + { + server = &channel->servers[i]; + /* We only need to register interest in UDP sockets if we have + * outstanding queries. + */ + if (active_queries && server->udp_socket != ARES_SOCKET_BAD) + { + if(sockindex >= numsocks) + break; + socks[sockindex] = server->udp_socket; + bitmap |= ARES_GETSOCK_READABLE(setbits, sockindex); + sockindex++; + } + /* We always register for TCP events, because we want to know + * when the other side closes the connection, so we don't waste + * time trying to use a broken connection. + */ + if (server->tcp_socket != ARES_SOCKET_BAD) + { + if(sockindex >= numsocks) + break; + socks[sockindex] = server->tcp_socket; + bitmap |= ARES_GETSOCK_READABLE(setbits, sockindex); + + if (server->qhead && active_queries) + /* then the tcp socket is also writable! */ + bitmap |= ARES_GETSOCK_WRITABLE(setbits, sockindex); + + sockindex++; + } + } + return bitmap; +} diff --git a/deps/c-ares/ares_init.c b/deps/c-ares/ares_init.c new file mode 100644 index 00000000000..0a481e156ee --- /dev/null +++ b/deps/c-ares/ares_init.c @@ -0,0 +1,1627 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef USE_WINSOCK +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "ares.h" +#include "inet_net_pton.h" +#include "ares_library_init.h" +#include "ares_private.h" + +#ifdef WATT32 +#undef WIN32 /* Redefined in MingW/MSVC headers */ +#endif + +static int init_by_options(ares_channel channel, const struct ares_options *options, + int optmask); +static int init_by_environment(ares_channel channel); +static int init_by_resolv_conf(ares_channel channel); +static int init_by_defaults(ares_channel channel); + +#ifndef WATT32 +static int config_nameserver(struct server_state **servers, int *nservers, + char *str); +#endif +static int set_search(ares_channel channel, const char *str); +static int set_options(ares_channel channel, const char *str); +static const char *try_option(const char *p, const char *q, const char *opt); +static int init_id_key(rc4_key* key,int key_data_len); + +#if !defined(WIN32) && !defined(WATT32) +static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat); +static int ip_addr(const char *s, int len, struct in_addr *addr); +static void natural_mask(struct apattern *pat); +static int config_domain(ares_channel channel, char *str); +static int config_lookup(ares_channel channel, const char *str, + const char *bindch, const char *filech); +static int config_sortlist(struct apattern **sortlist, int *nsort, + const char *str); +static char *try_config(char *s, const char *opt); +#endif + +#define ARES_CONFIG_CHECK(x) (x->lookups && x->nsort > -1 && \ + x->nservers > -1 && \ + x->ndomains > -1 && \ + x->ndots > -1 && x->timeout > -1 && \ + x->tries > -1) + +int ares_init(ares_channel *channelptr) +{ + return ares_init_options(channelptr, NULL, 0); +} + +int ares_init_options(ares_channel *channelptr, struct ares_options *options, + int optmask) +{ + ares_channel channel; + int i; + int status = ARES_SUCCESS; + struct timeval now; + +#ifdef CURLDEBUG + const char *env = getenv("CARES_MEMDEBUG"); + + if (env) + curl_memdebug(env); + env = getenv("CARES_MEMLIMIT"); + if (env) + curl_memlimit(atoi(env)); +#endif + + if (ares_library_initialized() != ARES_SUCCESS) + return ARES_ENOTINITIALIZED; + + channel = malloc(sizeof(struct ares_channeldata)); + if (!channel) { + *channelptr = NULL; + return ARES_ENOMEM; + } + + now = ares__tvnow(); + + /* Set everything to distinguished values so we know they haven't + * been set yet. + */ + channel->flags = -1; + channel->timeout = -1; + channel->tries = -1; + channel->ndots = -1; + channel->rotate = -1; + channel->udp_port = -1; + channel->tcp_port = -1; + channel->socket_send_buffer_size = -1; + channel->socket_receive_buffer_size = -1; + channel->nservers = -1; + channel->ndomains = -1; + channel->nsort = -1; + channel->tcp_connection_generation = 0; + channel->lookups = NULL; + channel->domains = NULL; + channel->sortlist = NULL; + channel->servers = NULL; + channel->sock_state_cb = NULL; + channel->sock_state_cb_data = NULL; + channel->sock_create_cb = NULL; + channel->sock_create_cb_data = NULL; + + channel->last_server = 0; + channel->last_timeout_processed = (time_t)now.tv_sec; + + /* Initialize our lists of queries */ + ares__init_list_head(&(channel->all_queries)); + for (i = 0; i < ARES_QID_TABLE_SIZE; i++) + { + ares__init_list_head(&(channel->queries_by_qid[i])); + } + for (i = 0; i < ARES_TIMEOUT_TABLE_SIZE; i++) + { + ares__init_list_head(&(channel->queries_by_timeout[i])); + } + + /* Initialize configuration by each of the four sources, from highest + * precedence to lowest. + */ + + if (status == ARES_SUCCESS) { + status = init_by_options(channel, options, optmask); + if (status != ARES_SUCCESS) + DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n", + ares_strerror(status))); + } + if (status == ARES_SUCCESS) { + status = init_by_environment(channel); + if (status != ARES_SUCCESS) + DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n", + ares_strerror(status))); + } + if (status == ARES_SUCCESS) { + status = init_by_resolv_conf(channel); + if (status != ARES_SUCCESS) + DEBUGF(fprintf(stderr, "Error: init_by_resolv_conf failed: %s\n", + ares_strerror(status))); + } + + /* + * No matter what failed or succeeded, seed defaults to provide + * useful behavior for things that we missed. + */ + status = init_by_defaults(channel); + if (status != ARES_SUCCESS) + DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n", + ares_strerror(status))); + + /* Generate random key */ + + if (status == ARES_SUCCESS) { + status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN); + if (status == ARES_SUCCESS) + channel->next_id = ares__generate_new_id(&channel->id_key); + else + DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n", + ares_strerror(status))); + } + + if (status != ARES_SUCCESS) + { + /* Something failed; clean up memory we may have allocated. */ + if (channel->servers) + free(channel->servers); + if (channel->domains) + { + for (i = 0; i < channel->ndomains; i++) + free(channel->domains[i]); + free(channel->domains); + } + if (channel->sortlist) + free(channel->sortlist); + if(channel->lookups) + free(channel->lookups); + free(channel); + return status; + } + + /* Trim to one server if ARES_FLAG_PRIMARY is set. */ + if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1) + channel->nservers = 1; + + ares__init_servers_state(channel); + + *channelptr = channel; + return ARES_SUCCESS; +} + +/* ares_dup() duplicates a channel handle with all its options and returns a + new channel handle */ +int ares_dup(ares_channel *dest, ares_channel src) +{ + struct ares_options opts; + struct ares_addr_node *servers; + int ipv6_nservers = 0; + int i, rc; + int optmask; + + *dest = NULL; /* in case of failure return NULL explicitly */ + + /* First get the options supported by the old ares_save_options() function, + which is most of them */ + rc = ares_save_options(src, &opts, &optmask); + if(rc) + return rc; + + /* Then create the new channel with those options */ + rc = ares_init_options(dest, &opts, optmask); + + /* destroy the options copy to not leak any memory */ + ares_destroy_options(&opts); + + if(rc) + return rc; + + /* Now clone the options that ares_save_options() doesn't support. */ + (*dest)->sock_create_cb = src->sock_create_cb; + (*dest)->sock_create_cb_data = src->sock_create_cb_data; + + /* Full name server cloning required when not all are IPv4 */ + for (i = 0; i < src->nservers; i++) + { + if (src->servers[i].addr.family != AF_INET) { + ipv6_nservers++; + break; + } + } + if (ipv6_nservers) { + rc = ares_get_servers(src, &servers); + if (rc != ARES_SUCCESS) + return rc; + rc = ares_set_servers(*dest, servers); + ares_free_data(servers); + if (rc != ARES_SUCCESS) + return rc; + } + + return ARES_SUCCESS; /* everything went fine */ +} + +/* Save options from initialized channel */ +int ares_save_options(ares_channel channel, struct ares_options *options, + int *optmask) +{ + int i, j; + int ipv4_nservers = 0; + + /* Zero everything out */ + memset(options, 0, sizeof(struct ares_options)); + + if (!ARES_CONFIG_CHECK(channel)) + return ARES_ENODATA; + + /* Traditionally the optmask wasn't saved in the channel struct so it was + recreated here. ROTATE is the first option that has no struct field of + its own in the public config struct */ + (*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TRIES|ARES_OPT_NDOTS| + ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB| + ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS| + ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS) | + (channel->optmask & ARES_OPT_ROTATE); + + /* Copy easy stuff */ + options->flags = channel->flags; + + /* We return full millisecond resolution but that's only because we don't + set the ARES_OPT_TIMEOUT anymore, only the new ARES_OPT_TIMEOUTMS */ + options->timeout = channel->timeout; + options->tries = channel->tries; + options->ndots = channel->ndots; + options->udp_port = (unsigned short)channel->udp_port; + options->tcp_port = (unsigned short)channel->tcp_port; + options->sock_state_cb = channel->sock_state_cb; + options->sock_state_cb_data = channel->sock_state_cb_data; + + /* Copy IPv4 servers */ + if (channel->nservers) { + for (i = 0; i < channel->nservers; i++) + { + if (channel->servers[i].addr.family == AF_INET) + ipv4_nservers++; + } + if (ipv4_nservers) { + options->servers = malloc(ipv4_nservers * sizeof(struct server_state)); + if (!options->servers) + return ARES_ENOMEM; + for (i = j = 0; i < channel->nservers; i++) + { + if (channel->servers[i].addr.family == AF_INET) + memcpy(&options->servers[j++], + &channel->servers[i].addr.addrV4, + sizeof(channel->servers[i].addr.addrV4)); + } + } + } + options->nservers = ipv4_nservers; + + /* copy domains */ + if (channel->ndomains) { + options->domains = malloc(channel->ndomains * sizeof(char *)); + if (!options->domains) + return ARES_ENOMEM; + + for (i = 0; i < channel->ndomains; i++) + { + options->ndomains = i; + options->domains[i] = strdup(channel->domains[i]); + if (!options->domains[i]) + return ARES_ENOMEM; + } + } + options->ndomains = channel->ndomains; + + /* copy lookups */ + if (channel->lookups) { + options->lookups = strdup(channel->lookups); + if (!options->lookups && channel->lookups) + return ARES_ENOMEM; + } + + /* copy sortlist */ + if (channel->nsort) { + options->sortlist = malloc(channel->nsort * sizeof(struct apattern)); + if (!options->sortlist) + return ARES_ENOMEM; + for (i = 0; i < channel->nsort; i++) + { + memcpy(&(options->sortlist[i]), &(channel->sortlist[i]), + sizeof(struct apattern)); + } + } + options->nsort = channel->nsort; + + return ARES_SUCCESS; +} + +static int init_by_options(ares_channel channel, + const struct ares_options *options, + int optmask) +{ + int i; + + /* Easy stuff. */ + if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1) + channel->flags = options->flags; + if ((optmask & ARES_OPT_TIMEOUTMS) && channel->timeout == -1) + channel->timeout = options->timeout; + else if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1) + channel->timeout = options->timeout * 1000; + if ((optmask & ARES_OPT_TRIES) && channel->tries == -1) + channel->tries = options->tries; + if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1) + channel->ndots = options->ndots; + if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1) + channel->rotate = 1; + if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1) + channel->udp_port = options->udp_port; + if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1) + channel->tcp_port = options->tcp_port; + if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL) + { + channel->sock_state_cb = options->sock_state_cb; + channel->sock_state_cb_data = options->sock_state_cb_data; + } + if ((optmask & ARES_OPT_SOCK_SNDBUF) + && channel->socket_send_buffer_size == -1) + channel->socket_send_buffer_size = options->socket_send_buffer_size; + if ((optmask & ARES_OPT_SOCK_RCVBUF) + && channel->socket_receive_buffer_size == -1) + channel->socket_receive_buffer_size = options->socket_receive_buffer_size; + + /* Copy the IPv4 servers, if given. */ + if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1) + { + /* Avoid zero size allocations at any cost */ + if (options->nservers > 0) + { + channel->servers = + malloc(options->nservers * sizeof(struct server_state)); + if (!channel->servers) + return ARES_ENOMEM; + for (i = 0; i < options->nservers; i++) + { + channel->servers[i].addr.family = AF_INET; + memcpy(&channel->servers[i].addr.addrV4, + &options->servers[i], + sizeof(channel->servers[i].addr.addrV4)); + } + } + channel->nservers = options->nservers; + } + + /* Copy the domains, if given. Keep channel->ndomains consistent so + * we can clean up in case of error. + */ + if ((optmask & ARES_OPT_DOMAINS) && channel->ndomains == -1) + { + /* Avoid zero size allocations at any cost */ + if (options->ndomains > 0) + { + channel->domains = malloc(options->ndomains * sizeof(char *)); + if (!channel->domains) + return ARES_ENOMEM; + for (i = 0; i < options->ndomains; i++) + { + channel->ndomains = i; + channel->domains[i] = strdup(options->domains[i]); + if (!channel->domains[i]) + return ARES_ENOMEM; + } + } + channel->ndomains = options->ndomains; + } + + /* Set lookups, if given. */ + if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups) + { + channel->lookups = strdup(options->lookups); + if (!channel->lookups) + return ARES_ENOMEM; + } + + /* copy sortlist */ + if ((optmask & ARES_OPT_SORTLIST) && channel->nsort == -1) + { + channel->sortlist = malloc(options->nsort * sizeof(struct apattern)); + if (!channel->sortlist) + return ARES_ENOMEM; + for (i = 0; i < options->nsort; i++) + { + memcpy(&(channel->sortlist[i]), &(options->sortlist[i]), + sizeof(struct apattern)); + } + channel->nsort = options->nsort; + } + + channel->optmask = optmask; + + return ARES_SUCCESS; +} + +static int init_by_environment(ares_channel channel) +{ + const char *localdomain, *res_options; + int status; + + localdomain = getenv("LOCALDOMAIN"); + if (localdomain && channel->ndomains == -1) + { + status = set_search(channel, localdomain); + if (status != ARES_SUCCESS) + return status; + } + + res_options = getenv("RES_OPTIONS"); + if (res_options) + { + status = set_options(channel, res_options); + if (status != ARES_SUCCESS) + return status; + } + + return ARES_SUCCESS; +} + +#ifdef WIN32 +/* + * Warning: returns a dynamically allocated buffer, the user MUST + * use free() if the function returns 1 + */ +static int get_res_nt(HKEY hKey, const char *subkey, char **obuf) +{ + /* Test for the size we need */ + DWORD size = 0; + int result; + + result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size); + if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size) + return 0; + *obuf = malloc(size+1); + if (!*obuf) + return 0; + + if (RegQueryValueEx(hKey, subkey, 0, NULL, + (LPBYTE)*obuf, &size) != ERROR_SUCCESS) + { + free(*obuf); + return 0; + } + if (size == 1) + { + free(*obuf); + return 0; + } + return 1; +} + +static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf) +{ + char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */ + DWORD enum_size = 39; + int idx = 0; + HKEY hVal; + + while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0, + NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) + { + int rc; + + enum_size = 39; + if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) != + ERROR_SUCCESS) + continue; + rc = get_res_nt(hVal, subkey, obuf); + RegCloseKey(hVal); + if (rc) + return 1; + } + return 0; +} + +static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size) +{ + FIXED_INFO *fi, *newfi; + DWORD size = sizeof (*fi); + IP_ADDR_STRING *ipAddr; + int i, count = 0; + int debug = 0; + size_t ip_size = sizeof("255.255.255.255,")-1; + size_t left = ret_size; + char *ret = ret_buf; + HRESULT res; + + fi = malloc(size); + if (!fi) + return 0; + + res = (*ares_fpGetNetworkParams) (fi, &size); + if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) + goto quit; + + newfi = realloc(fi, size); + if (!newfi) + goto quit; + + fi = newfi; + res = (*ares_fpGetNetworkParams) (fi, &size); + if (res != ERROR_SUCCESS) + goto quit; + + if (debug) + { + printf ("Host Name: %s\n", fi->HostName); + printf ("Domain Name: %s\n", fi->DomainName); + printf ("DNS Servers:\n" + " %s (primary)\n", fi->DnsServerList.IpAddress.String); + } + if (strlen(fi->DnsServerList.IpAddress.String) > 0 && + inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE && + left > ip_size) + { + ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String); + left -= ret - ret_buf; + count++; + } + + for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size; + ipAddr = ipAddr->Next, i++) + { + if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE) + { + ret += sprintf (ret, "%s,", ipAddr->IpAddress.String); + left -= ret - ret_buf; + count++; + } + if (debug) + printf (" %s (secondary %d)\n", ipAddr->IpAddress.String, i+1); + } + +quit: + if (fi) + free(fi); + + if (debug && left <= ip_size) + printf ("Too many nameservers. Truncating to %d addressess", count); + if (ret > ret_buf) + ret[-1] = '\0'; + return count; +} +#endif + +static int init_by_resolv_conf(ares_channel channel) +{ +#ifndef WATT32 + char *line = NULL; +#endif + int status = -1, nservers = 0, nsort = 0; + struct server_state *servers = NULL; + struct apattern *sortlist = NULL; + +#ifdef WIN32 + + /* + NameServer info via IPHLPAPI (IP helper API): + GetNetworkParams() should be the trusted source for this. + Available in Win-98/2000 and later. If that fail, fall-back to + registry information. + + NameServer Registry: + + On Windows 9X, the DNS server can be found in: +HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer + + On Windows NT/2000/XP/2003: +HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer + or +HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer + or +HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ +NameServer + or +HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ +DhcpNameServer + */ + + HKEY mykey; + HKEY subkey; + DWORD data_type; + DWORD bytes; + DWORD result; + char buf[256]; + + if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */ + return ARES_SUCCESS; + + if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0) + { + status = config_nameserver(&servers, &nservers, buf); + if (status == ARES_SUCCESS) + goto okay; + } + + if (IS_NT()) + { + if (RegOpenKeyEx( + HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, + KEY_READ, &mykey + ) == ERROR_SUCCESS) + { + RegOpenKeyEx(mykey, "Interfaces", 0, + KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey); + if (get_res_nt(mykey, NAMESERVER, &line)) + { + status = config_nameserver(&servers, &nservers, line); + free(line); + } + else if (get_res_nt(mykey, DHCPNAMESERVER, &line)) + { + status = config_nameserver(&servers, &nservers, line); + free(line); + } + /* Try the interfaces */ + else if (get_res_interfaces_nt(subkey, NAMESERVER, &line)) + { + status = config_nameserver(&servers, &nservers, line); + free(line); + } + else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line)) + { + status = config_nameserver(&servers, &nservers, line); + free(line); + } + RegCloseKey(subkey); + RegCloseKey(mykey); + } + } + else + { + if (RegOpenKeyEx( + HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, + KEY_READ, &mykey + ) == ERROR_SUCCESS) + { + if ((result = RegQueryValueEx( + mykey, NAMESERVER, NULL, &data_type, + NULL, &bytes + ) + ) == ERROR_SUCCESS || + result == ERROR_MORE_DATA) + { + if (bytes) + { + line = malloc(bytes+1); + if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type, + (unsigned char *)line, &bytes) == + ERROR_SUCCESS) + { + status = config_nameserver(&servers, &nservers, line); + } + free(line); + } + } + } + RegCloseKey(mykey); + } + + if (status == ARES_SUCCESS) + status = ARES_EOF; + else + /* Catch the case when all the above checks fail (which happens when there + is no network card or the cable is unplugged) */ + status = ARES_EFILE; + +#elif defined(__riscos__) + + /* Under RISC OS, name servers are listed in the + system variable Inet$Resolvers, space separated. */ + + line = getenv("Inet$Resolvers"); + status = ARES_EOF; + if (line) { + char *resolvers = strdup(line), *pos, *space; + + if (!resolvers) + return ARES_ENOMEM; + + pos = resolvers; + do { + space = strchr(pos, ' '); + if (space) + *space = '\0'; + status = config_nameserver(&servers, &nservers, pos); + if (status != ARES_SUCCESS) + break; + pos = space + 1; + } while (space); + + if (status == ARES_SUCCESS) + status = ARES_EOF; + + free(resolvers); + } + +#elif defined(WATT32) + int i; + + sock_init(); + for (i = 0; def_nameservers[i]; i++) + ; + if (i == 0) + return ARES_SUCCESS; /* use localhost DNS server */ + + nservers = i; + servers = calloc(i, sizeof(struct server_state)); + if (!servers) + return ARES_ENOMEM; + + for (i = 0; def_nameservers[i]; i++) + servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]); + status = ARES_EOF; + +#else + { + char *p; + FILE *fp; + size_t linesize; + int error; + + /* Don't read resolv.conf and friends if we don't have to */ + if (ARES_CONFIG_CHECK(channel)) + return ARES_SUCCESS; + + fp = fopen(PATH_RESOLV_CONF, "r"); + if (fp) { + while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) + { + if ((p = try_config(line, "domain")) && channel->ndomains == -1) + status = config_domain(channel, p); + else if ((p = try_config(line, "lookup")) && !channel->lookups) + status = config_lookup(channel, p, "bind", "file"); + else if ((p = try_config(line, "search")) && channel->ndomains == -1) + status = set_search(channel, p); + else if ((p = try_config(line, "nameserver")) && channel->nservers == -1) + status = config_nameserver(&servers, &nservers, p); + else if ((p = try_config(line, "sortlist")) && channel->nsort == -1) + status = config_sortlist(&sortlist, &nsort, p); + else if ((p = try_config(line, "options"))) + status = set_options(channel, p); + else + status = ARES_SUCCESS; + if (status != ARES_SUCCESS) + break; + } + fclose(fp); + } + else { + error = ERRNO; + switch(error) { + case ENOENT: + case ESRCH: + status = ARES_EOF; + break; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF)); + status = ARES_EFILE; + } + } + + if ((status == ARES_EOF) && (!channel->lookups)) { + /* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */ + fp = fopen("/etc/nsswitch.conf", "r"); + if (fp) { + while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) + { + if ((p = try_config(line, "hosts:")) && !channel->lookups) + status = config_lookup(channel, p, "dns", "files"); + } + fclose(fp); + } + else { + error = ERRNO; + switch(error) { + case ENOENT: + case ESRCH: + status = ARES_EOF; + break; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf")); + status = ARES_EFILE; + } + } + } + + if ((status == ARES_EOF) && (!channel->lookups)) { + /* Linux / GNU libc 2.x and possibly others have host.conf */ + fp = fopen("/etc/host.conf", "r"); + if (fp) { + while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) + { + if ((p = try_config(line, "order")) && !channel->lookups) + status = config_lookup(channel, p, "bind", "hosts"); + } + fclose(fp); + } + else { + error = ERRNO; + switch(error) { + case ENOENT: + case ESRCH: + status = ARES_EOF; + break; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf")); + status = ARES_EFILE; + } + } + } + + if ((status == ARES_EOF) && (!channel->lookups)) { + /* Tru64 uses /etc/svc.conf */ + fp = fopen("/etc/svc.conf", "r"); + if (fp) { + while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) + { + if ((p = try_config(line, "hosts=")) && !channel->lookups) + status = config_lookup(channel, p, "bind", "local"); + } + fclose(fp); + } + else { + error = ERRNO; + switch(error) { + case ENOENT: + case ESRCH: + status = ARES_EOF; + break; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf")); + status = ARES_EFILE; + } + } + } + + if(line) + free(line); + } + +#endif + + /* Handle errors. */ + if (status != ARES_EOF) + { + if (servers != NULL) + free(servers); + if (sortlist != NULL) + free(sortlist); + return status; + } + + /* If we got any name server entries, fill them in. */ +#ifdef WIN32 +okay: +#endif + if (servers) + { + channel->servers = servers; + channel->nservers = nservers; + } + + /* If we got any sortlist entries, fill them in. */ + if (sortlist) + { + channel->sortlist = sortlist; + channel->nsort = nsort; + } + + return ARES_SUCCESS; +} + +static int init_by_defaults(ares_channel channel) +{ + char *hostname = NULL; + int rc = ARES_SUCCESS; +#ifdef HAVE_GETHOSTNAME + char *dot; +#endif + + if (channel->flags == -1) + channel->flags = 0; + if (channel->timeout == -1) + channel->timeout = DEFAULT_TIMEOUT; + if (channel->tries == -1) + channel->tries = DEFAULT_TRIES; + if (channel->ndots == -1) + channel->ndots = 1; + if (channel->rotate == -1) + channel->rotate = 0; + if (channel->udp_port == -1) + channel->udp_port = htons(NAMESERVER_PORT); + if (channel->tcp_port == -1) + channel->tcp_port = htons(NAMESERVER_PORT); + + if (channel->nservers == -1) { + /* If nobody specified servers, try a local named. */ + channel->servers = malloc(sizeof(struct server_state)); + if (!channel->servers) { + rc = ARES_ENOMEM; + goto error; + } + channel->servers[0].addr.family = AF_INET; + channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK); + channel->nservers = 1; + } + +#ifdef ENAMETOOLONG +#define toolong(x) (x == -1) && ((ENAMETOOLONG == errno) || (EINVAL == errno)) +#else +#define toolong(x) (x == -1) && (EINVAL == errno) +#endif + + if (channel->ndomains == -1) { + /* Derive a default domain search list from the kernel hostname, + * or set it to empty if the hostname isn't helpful. + */ + size_t len = 64; + int res; + channel->ndomains = 0; /* default to none */ + +#ifdef HAVE_GETHOSTNAME + hostname = malloc(len); + if(!hostname) { + rc = ARES_ENOMEM; + goto error; + } + + do { + res = gethostname(hostname, len); + + if(toolong(res)) { + char *p; + len *= 2; + p = realloc(hostname, len); + if(!p) { + rc = ARES_ENOMEM; + goto error; + } + hostname = p; + continue; + } + else if(res) { + rc = ARES_EBADNAME; + goto error; + } + + } while(0); + + dot = strchr(hostname, '.'); + if (dot) { + /* a dot was found */ + channel->domains = malloc(sizeof(char *)); + if (!channel->domains) { + rc = ARES_ENOMEM; + goto error; + } + channel->domains[0] = strdup(dot + 1); + if (!channel->domains[0]) { + rc = ARES_ENOMEM; + goto error; + } + channel->ndomains = 1; + } +#endif + } + + if (channel->nsort == -1) { + channel->sortlist = NULL; + channel->nsort = 0; + } + + if (!channel->lookups) { + channel->lookups = strdup("fb"); + if (!channel->lookups) + rc = ARES_ENOMEM; + } + + error: + if(rc) { + if(channel->servers) + free(channel->servers); + + if(channel->domains && channel->domains[0]) + free(channel->domains[0]); + if(channel->domains) + free(channel->domains); + if(channel->lookups) + free(channel->lookups); + } + + if(hostname) + free(hostname); + + return rc; +} + +#if !defined(WIN32) && !defined(WATT32) +static int config_domain(ares_channel channel, char *str) +{ + char *q; + + /* Set a single search domain. */ + q = str; + while (*q && !ISSPACE(*q)) + q++; + *q = '\0'; + return set_search(channel, str); +} + +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ + defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) + /* workaround icc 9.1 optimizer issue */ +# define vqualifier volatile +#else +# define vqualifier +#endif + +static int config_lookup(ares_channel channel, const char *str, + const char *bindch, const char *filech) +{ + char lookups[3], *l; + const char *vqualifier p; + + /* Set the lookup order. Only the first letter of each work + * is relevant, and it has to be "b" for DNS or "f" for the + * host file. Ignore everything else. + */ + l = lookups; + p = str; + while (*p) + { + if ((*p == *bindch || *p == *filech) && l < lookups + 2) { + if (*p == *bindch) *l++ = 'b'; + else *l++ = 'f'; + } + while (*p && !ISSPACE(*p) && (*p != ',')) + p++; + while (*p && (ISSPACE(*p) || (*p == ','))) + p++; + } + *l = '\0'; + channel->lookups = strdup(lookups); + return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM; +} +#endif /* !WIN32 & !WATT32 */ + +#ifndef WATT32 +static int config_nameserver(struct server_state **servers, int *nservers, + char *str) +{ + struct ares_addr host; + struct server_state *newserv; + char *p, *txtaddr; + /* On Windows, there may be more than one nameserver specified in the same + * registry key, so we parse input as a space or comma seperated list. + */ + for (p = str; p;) + { + /* Skip whitespace and commas. */ + while (*p && (ISSPACE(*p) || (*p == ','))) + p++; + if (!*p) + /* No more input, done. */ + break; + + /* Pointer to start of IPv4 or IPv6 address part. */ + txtaddr = p; + + /* Advance past this address. */ + while (*p && !ISSPACE(*p) && (*p != ',')) + p++; + if (*p) + /* Null terminate this address. */ + *p++ = '\0'; + else + /* Reached end of input, done when this address is processed. */ + p = NULL; + + /* Convert textual address to binary format. */ + if (ares_inet_pton(AF_INET, txtaddr, &host.addrV4) == 1) + host.family = AF_INET; + else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1) + host.family = AF_INET6; + else + continue; + + /* Resize servers state array. */ + newserv = realloc(*servers, (*nservers + 1) * + sizeof(struct server_state)); + if (!newserv) + return ARES_ENOMEM; + + /* Store address data. */ + newserv[*nservers].addr.family = host.family; + if (host.family == AF_INET) + memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4, + sizeof(host.addrV4)); + else + memcpy(&newserv[*nservers].addr.addrV6, &host.addrV6, + sizeof(host.addrV6)); + + /* Update arguments. */ + *servers = newserv; + *nservers += 1; + } + + return ARES_SUCCESS; +} + +#ifndef WIN32 +static int config_sortlist(struct apattern **sortlist, int *nsort, + const char *str) +{ + struct apattern pat; + const char *q; + + /* Add sortlist entries. */ + while (*str && *str != ';') + { + int bits; + char ipbuf[16], ipbufpfx[32]; + /* Find just the IP */ + q = str; + while (*q && *q != '/' && *q != ';' && !ISSPACE(*q)) + q++; + memcpy(ipbuf, str, (int)(q-str)); + ipbuf[(int)(q-str)] = '\0'; + /* Find the prefix */ + if (*q == '/') + { + const char *str2 = q+1; + while (*q && *q != ';' && !ISSPACE(*q)) + q++; + memcpy(ipbufpfx, str, (int)(q-str)); + ipbufpfx[(int)(q-str)] = '\0'; + str = str2; + } + else + ipbufpfx[0] = '\0'; + /* Lets see if it is CIDR */ + /* First we'll try IPv6 */ + if ((bits = ares_inet_net_pton(AF_INET6, ipbufpfx[0] ? ipbufpfx : ipbuf, + &pat.addrV6, + sizeof(pat.addrV6))) > 0) + { + pat.type = PATTERN_CIDR; + pat.mask.bits = (unsigned short)bits; + pat.family = AF_INET6; + if (!sortlist_alloc(sortlist, nsort, &pat)) + return ARES_ENOMEM; + } + if (ipbufpfx[0] && + (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4, + sizeof(pat.addrV4))) > 0) + { + pat.type = PATTERN_CIDR; + pat.mask.bits = (unsigned short)bits; + pat.family = AF_INET; + if (!sortlist_alloc(sortlist, nsort, &pat)) + return ARES_ENOMEM; + } + /* See if it is just a regular IP */ + else if (ip_addr(ipbuf, (int)(q-str), &pat.addrV4) == 0) + { + if (ipbufpfx[0]) + { + memcpy(ipbuf, str, (int)(q-str)); + ipbuf[(int)(q-str)] = '\0'; + if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr4) != 0) + natural_mask(&pat); + } + else + natural_mask(&pat); + pat.family = AF_INET; + pat.type = PATTERN_MASK; + if (!sortlist_alloc(sortlist, nsort, &pat)) + return ARES_ENOMEM; + } + else + { + while (*q && *q != ';' && !ISSPACE(*q)) + q++; + } + str = q; + while (ISSPACE(*str)) + str++; + } + + return ARES_SUCCESS; +} +#endif /* !WIN32 */ +#endif /* !WATT32 */ + +static int set_search(ares_channel channel, const char *str) +{ + int n; + const char *p, *q; + + if(channel->ndomains != -1) { + /* if we already have some domains present, free them first */ + for(n=0; n < channel->ndomains; n++) + free(channel->domains[n]); + free(channel->domains); + channel->domains = NULL; + channel->ndomains = -1; + } + + /* Count the domains given. */ + n = 0; + p = str; + while (*p) + { + while (*p && !ISSPACE(*p)) + p++; + while (ISSPACE(*p)) + p++; + n++; + } + + if (!n) + { + channel->ndomains = 0; + return ARES_SUCCESS; + } + + channel->domains = malloc(n * sizeof(char *)); + if (!channel->domains) + return ARES_ENOMEM; + + /* Now copy the domains. */ + n = 0; + p = str; + while (*p) + { + channel->ndomains = n; + q = p; + while (*q && !ISSPACE(*q)) + q++; + channel->domains[n] = malloc(q - p + 1); + if (!channel->domains[n]) + return ARES_ENOMEM; + memcpy(channel->domains[n], p, q - p); + channel->domains[n][q - p] = 0; + p = q; + while (ISSPACE(*p)) + p++; + n++; + } + channel->ndomains = n; + + return ARES_SUCCESS; +} + +static int set_options(ares_channel channel, const char *str) +{ + const char *p, *q, *val; + + p = str; + while (*p) + { + q = p; + while (*q && !ISSPACE(*q)) + q++; + val = try_option(p, q, "ndots:"); + if (val && channel->ndots == -1) + channel->ndots = atoi(val); + val = try_option(p, q, "retrans:"); + if (val && channel->timeout == -1) + channel->timeout = atoi(val); + val = try_option(p, q, "retry:"); + if (val && channel->tries == -1) + channel->tries = atoi(val); + val = try_option(p, q, "rotate"); + if (val && channel->rotate == -1) + channel->rotate = 1; + p = q; + while (ISSPACE(*p)) + p++; + } + + return ARES_SUCCESS; +} + +static const char *try_option(const char *p, const char *q, const char *opt) +{ + size_t len = strlen(opt); + return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL; +} + +#if !defined(WIN32) && !defined(WATT32) +static char *try_config(char *s, const char *opt) +{ + size_t len; + char *p; + char *q; + + if (!s || !opt) + /* no line or no option */ + return NULL; + + /* trim line comment */ + p = s; + while (*p && (*p != '#')) + p++; + *p = '\0'; + + /* trim trailing whitespace */ + q = p - 1; + while ((q >= s) && ISSPACE(*q)) + q--; + *++q = '\0'; + + /* skip leading whitespace */ + p = s; + while (*p && ISSPACE(*p)) + p++; + + if (!*p) + /* empty line */ + return NULL; + + if ((len = strlen(opt)) == 0) + /* empty option */ + return NULL; + + if (strncmp(p, opt, len) != 0) + /* line and option do not match */ + return NULL; + + /* skip over given option name */ + p += len; + + if (!*p) + /* no option value */ + return NULL; + + if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p)) + /* whitespace between option name and value is mandatory + for given option names which do not end with ':' or '=' */ + return NULL; + + /* skip over whitespace */ + while (*p && ISSPACE(*p)) + p++; + + if (!*p) + /* no option value */ + return NULL; + + /* return pointer to option value */ + return p; +} + +static int sortlist_alloc(struct apattern **sortlist, int *nsort, + struct apattern *pat) +{ + struct apattern *newsort; + newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern)); + if (!newsort) + return 0; + newsort[*nsort] = *pat; + *sortlist = newsort; + (*nsort)++; + return 1; +} + +static int ip_addr(const char *ipbuf, int len, struct in_addr *addr) +{ + + /* Four octets and three periods yields at most 15 characters. */ + if (len > 15) + return -1; + + addr->s_addr = inet_addr(ipbuf); + if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0) + return -1; + return 0; +} + +static void natural_mask(struct apattern *pat) +{ + struct in_addr addr; + + /* Store a host-byte-order copy of pat in a struct in_addr. Icky, + * but portable. + */ + addr.s_addr = ntohl(pat->addrV4.s_addr); + + /* This is out of date in the CIDR world, but some people might + * still rely on it. + */ + if (IN_CLASSA(addr.s_addr)) + pat->mask.addr4.s_addr = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(addr.s_addr)) + pat->mask.addr4.s_addr = htonl(IN_CLASSB_NET); + else + pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET); +} +#endif /* !WIN32 && !WATT32 */ + +/* initialize an rc4 key. If possible a cryptographically secure random key + is generated using a suitable function (for example win32's RtlGenRandom as + described in + http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx + otherwise the code defaults to cross-platform albeit less secure mechanism + using rand +*/ +static void randomize_key(unsigned char* key,int key_data_len) +{ + int randomized = 0; + int counter=0; +#ifdef WIN32 + BOOLEAN res; + if (ares_fpSystemFunction036) + { + res = (*ares_fpSystemFunction036) (key, key_data_len); + if (res) + randomized = 1; + } +#else /* !WIN32 */ +#ifdef RANDOM_FILE + FILE *f = fopen(RANDOM_FILE, "rb"); + if(f) { + counter = fread(key, 1, key_data_len, f); + fclose(f); + } +#endif +#endif /* WIN32 */ + + if ( !randomized ) { + for (;counterstate[0]; + for(counter = 0; counter < 256; counter++) + /* unnecessary AND but it keeps some compilers happier */ + state[counter] = (unsigned char)(counter & 0xff); + randomize_key(key->state,key_data_len); + key->x = 0; + key->y = 0; + index1 = 0; + index2 = 0; + for(counter = 0; counter < 256; counter++) + { + index2 = (unsigned char)((key_data_ptr[index1] + state[counter] + + index2) % 256); + ARES_SWAP_BYTE(&state[counter], &state[index2]); + + index1 = (unsigned char)((index1 + 1) % key_data_len); + } + free(key_data_ptr); + return ARES_SUCCESS; +} + +unsigned short ares__generate_new_id(rc4_key* key) +{ + unsigned short r=0; + ares__rc4(key, (unsigned char *)&r, sizeof(r)); + return r; +} + +void ares_set_socket_callback(ares_channel channel, + ares_sock_create_callback cb, + void *data) +{ + channel->sock_create_cb = cb; + channel->sock_create_cb_data = data; +} + +void ares__init_servers_state(ares_channel channel) +{ + struct server_state *server; + int i; + + for (i = 0; i < channel->nservers; i++) + { + server = &channel->servers[i]; + server->udp_socket = ARES_SOCKET_BAD; + server->tcp_socket = ARES_SOCKET_BAD; + server->tcp_connection_generation = ++channel->tcp_connection_generation; + server->tcp_lenbuf_pos = 0; + server->tcp_buffer_pos = 0; + server->tcp_buffer = NULL; + server->tcp_length = 0; + server->qhead = NULL; + server->qtail = NULL; + ares__init_list_head(&server->queries_to_server); + server->channel = channel; + server->is_broken = 0; + } +} diff --git a/deps/c-ares/ares_ipv6.h b/deps/c-ares/ares_ipv6.h new file mode 100644 index 00000000000..4a97199c3b2 --- /dev/null +++ b/deps/c-ares/ares_ipv6.h @@ -0,0 +1,75 @@ +/* $Id$ */ + +/* Copyright (C) 2005 by Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef ARES_IPV6_H +#define ARES_IPV6_H + +#ifndef HAVE_PF_INET6 +#define PF_INET6 AF_INET6 +#endif + +#ifndef HAVE_STRUCT_SOCKADDR_IN6 +struct sockaddr_in6 +{ + unsigned short sin6_family; + unsigned short sin6_port; + unsigned long sin6_flowinfo; + struct ares_in6_addr sin6_addr; + unsigned int sin6_scope_id; +}; +#endif + +#ifndef HAVE_STRUCT_ADDRINFO +struct addrinfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + ares_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif + +#ifndef NS_IN6ADDRSZ +#if SIZEOF_STRUCT_IN6_ADDR == 0 +/* We cannot have it set to zero, so we pick a fixed value here */ +#define NS_IN6ADDRSZ 16 +#else +#define NS_IN6ADDRSZ SIZEOF_STRUCT_IN6_ADDR +#endif +#endif + +#ifndef NS_INADDRSZ +#define NS_INADDRSZ SIZEOF_STRUCT_IN_ADDR +#endif + +#ifndef NS_INT16SZ +#define NS_INT16SZ 2 +#endif + +#ifndef IF_NAMESIZE +#ifdef IFNAMSIZ +#define IF_NAMESIZE IFNAMSIZ +#else +#define IF_NAMESIZE 256 +#endif +#endif + +#endif /* ARES_IPV6_H */ diff --git a/deps/c-ares/ares_library_init.c b/deps/c-ares/ares_library_init.c new file mode 100644 index 00000000000..aac34eaf48c --- /dev/null +++ b/deps/c-ares/ares_library_init.c @@ -0,0 +1,133 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2004-2009 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#include "ares.h" +#include "ares_library_init.h" +#include "ares_private.h" + +/* library-private global and unique instance vars */ + +#ifdef USE_WINSOCK +fpGetNetworkParams_t ares_fpGetNetworkParams = ZERO_NULL; +fpSystemFunction036_t ares_fpSystemFunction036 = ZERO_NULL; +#endif + +/* library-private global vars with source visibility restricted to this file */ + +static unsigned int ares_initialized; +static int ares_init_flags; + +#ifdef USE_WINSOCK +static HMODULE hnd_iphlpapi; +static HMODULE hnd_advapi32; +#endif + + +static int ares_win32_init(void) +{ +#ifdef USE_WINSOCK + + hnd_iphlpapi = 0; + hnd_iphlpapi = LoadLibrary("iphlpapi.dll"); + if (!hnd_iphlpapi) + return ARES_ELOADIPHLPAPI; + + ares_fpGetNetworkParams = (fpGetNetworkParams_t) + GetProcAddress(hnd_iphlpapi, "GetNetworkParams"); + if (!ares_fpGetNetworkParams) + { + FreeLibrary(hnd_iphlpapi); + return ARES_EADDRGETNETWORKPARAMS; + } + + /* + * When advapi32.dll is unavailable or advapi32.dll has no SystemFunction036, + * also known as RtlGenRandom, which is the case for Windows versions prior + * to WinXP then c-ares uses portable rand() function. Then don't error here. + */ + + hnd_advapi32 = 0; + hnd_advapi32 = LoadLibrary("advapi32.dll"); + if (hnd_advapi32) + { + ares_fpSystemFunction036 = (fpSystemFunction036_t) + GetProcAddress(hnd_advapi32, "SystemFunction036"); + } + +#endif + return ARES_SUCCESS; +} + + +static void ares_win32_cleanup(void) +{ +#ifdef USE_WINSOCK + if (hnd_advapi32) + FreeLibrary(hnd_advapi32); + if (hnd_iphlpapi) + FreeLibrary(hnd_iphlpapi); +#endif +} + + +int ares_library_init(int flags) +{ + int res; + + if (ares_initialized) + return ARES_SUCCESS; + ares_initialized++; + + if (flags & ARES_LIB_INIT_WIN32) + { + res = ares_win32_init(); + if (res != ARES_SUCCESS) + return res; + } + + ares_init_flags = flags; + + return ARES_SUCCESS; +} + + +void ares_library_cleanup(void) +{ + if (!ares_initialized) + return; + ares_initialized--; + + if (ares_init_flags & ARES_LIB_INIT_WIN32) + ares_win32_cleanup(); + + ares_init_flags = ARES_LIB_INIT_NONE; +} + + +int ares_library_initialized(void) +{ +#ifdef USE_WINSOCK + if (!ares_initialized) + return ARES_ENOTINITIALIZED; +#endif + return ARES_SUCCESS; +} + + diff --git a/deps/c-ares/ares_library_init.h b/deps/c-ares/ares_library_init.h new file mode 100644 index 00000000000..515c17d82f9 --- /dev/null +++ b/deps/c-ares/ares_library_init.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CARES_LIBRARY_INIT_H +#define HEADER_CARES_LIBRARY_INIT_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2004-2009 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef USE_WINSOCK + +#include + +typedef DWORD (WINAPI *fpGetNetworkParams_t) (FIXED_INFO*, DWORD*); +typedef BOOLEAN (APIENTRY *fpSystemFunction036_t) (void*, ULONG); + +/* Forward-declaration of variables defined in ares_library_init.c */ +/* that are global and unique instances for whole c-ares library. */ + +extern fpGetNetworkParams_t ares_fpGetNetworkParams; +extern fpSystemFunction036_t ares_fpSystemFunction036; + +#endif /* USE_WINSOCK */ + +#endif /* HEADER_CARES_LIBRARY_INIT_H */ + diff --git a/deps/c-ares/ares_llist.c b/deps/c-ares/ares_llist.c new file mode 100644 index 00000000000..f261dc73b3d --- /dev/null +++ b/deps/c-ares/ares_llist.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#include "ares.h" +#include "ares_private.h" + +/* Routines for managing doubly-linked circular linked lists with a + * dummy head. + */ + +/* Initialize a new head node */ +void ares__init_list_head(struct list_node* head) { + head->prev = head; + head->next = head; + head->data = NULL; +} + +/* Initialize a list node */ +void ares__init_list_node(struct list_node* node, void* d) { + node->prev = NULL; + node->next = NULL; + node->data = d; +} + +/* Returns true iff the given list is empty */ +int ares__is_list_empty(struct list_node* head) { + return ((head->next == head) && (head->prev == head)); +} + +/* Inserts new_node before old_node */ +void ares__insert_in_list(struct list_node* new_node, + struct list_node* old_node) { + new_node->next = old_node; + new_node->prev = old_node->prev; + old_node->prev->next = new_node; + old_node->prev = new_node; +} + +/* Removes the node from the list it's in, if any */ +void ares__remove_from_list(struct list_node* node) { + if (node->next != NULL) { + node->prev->next = node->next; + node->next->prev = node->prev; + node->prev = NULL; + node->next = NULL; + } +} + +/* Swap the contents of two lists */ +void ares__swap_lists(struct list_node* head_a, + struct list_node* head_b) { + int is_a_empty = ares__is_list_empty(head_a); + int is_b_empty = ares__is_list_empty(head_b); + struct list_node old_a = *head_a; + struct list_node old_b = *head_b; + + if (is_a_empty) { + ares__init_list_head(head_b); + } else { + *head_b = old_a; + old_a.next->prev = head_b; + old_a.prev->next = head_b; + } + if (is_b_empty) { + ares__init_list_head(head_a); + } else { + *head_a = old_b; + old_b.next->prev = head_a; + old_b.prev->next = head_a; + } +} diff --git a/deps/c-ares/ares_llist.h b/deps/c-ares/ares_llist.h new file mode 100644 index 00000000000..d20af7e150f --- /dev/null +++ b/deps/c-ares/ares_llist.h @@ -0,0 +1,43 @@ +#ifndef __ARES_LLIST_H +#define __ARES_LLIST_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +/* Node definition for circular, doubly-linked list */ +struct list_node { + struct list_node *prev; + struct list_node *next; + void* data; +}; + +void ares__init_list_head(struct list_node* head); + +void ares__init_list_node(struct list_node* node, void* d); + +int ares__is_list_empty(struct list_node* head); + +void ares__insert_in_list(struct list_node* new_node, + struct list_node* old_node); + +void ares__remove_from_list(struct list_node* node); + +void ares__swap_lists(struct list_node* head_a, + struct list_node* head_b); + +#endif /* __ARES_LLIST_H */ diff --git a/deps/c-ares/ares_mkquery.c b/deps/c-ares/ares_mkquery.c new file mode 100644 index 00000000000..56571885cb6 --- /dev/null +++ b/deps/c-ares/ares_mkquery.c @@ -0,0 +1,196 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +/* Header format, from RFC 1035: + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ID | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QDCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ANCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | NSCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ARCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * + * AA, TC, RA, and RCODE are only set in responses. Brief description + * of the remaining fields: + * ID Identifier to match responses with queries + * QR Query (0) or response (1) + * Opcode For our purposes, always QUERY + * RD Recursion desired + * Z Reserved (zero) + * QDCOUNT Number of queries + * ANCOUNT Number of answers + * NSCOUNT Number of name server records + * ARCOUNT Number of additional records + * + * Question format, from RFC 1035: + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | | + * / QNAME / + * / / + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QTYPE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QCLASS | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * + * The query name is encoded as a series of labels, each represented + * as a one-byte length (maximum 63) followed by the text of the + * label. The list is terminated by a label of length zero (which can + * be thought of as the root domain). + */ + +int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id, + int rd, unsigned char **buf, int *buflen) +{ + int len; + unsigned char *q; + const char *p; + + /* Set our results early, in case we bail out early with an error. */ + *buflen = 0; + *buf = NULL; + + /* Compute the length of the encoded name so we can check buflen. + * Start counting at 1 for the zero-length label at the end. */ + len = 1; + for (p = name; *p; p++) + { + if (*p == '\\' && *(p + 1) != 0) + p++; + len++; + } + /* If there are n periods in the name, there are n + 1 labels, and + * thus n + 1 length fields, unless the name is empty or ends with a + * period. So add 1 unless name is empty or ends with a period. + */ + if (*name && *(p - 1) != '.') + len++; + + /* Immediately reject names that are longer than the maximum of 255 + * bytes that's specified in RFC 1035 ("To simplify implementations, + * the total length of a domain name (i.e., label octets and label + * length octets) is restricted to 255 octets or less."). We aren't + * doing this just to be a stickler about RFCs. For names that are + * too long, 'dnscache' closes its TCP connection to us immediately + * (when using TCP) and ignores the request when using UDP, and + * BIND's named returns ServFail (TCP or UDP). Sending a request + * that we know will cause 'dnscache' to close the TCP connection is + * painful, since that makes any other outstanding requests on that + * connection fail. And sending a UDP request that we know + * 'dnscache' will ignore is bad because resources will be tied up + * until we time-out the request. + */ + if (len > MAXCDNAME) + return ARES_EBADNAME; + + *buflen = len + HFIXEDSZ + QFIXEDSZ; + *buf = malloc(*buflen); + if (!*buf) + return ARES_ENOMEM; + + /* Set up the header. */ + q = *buf; + memset(q, 0, HFIXEDSZ); + DNS_HEADER_SET_QID(q, id); + DNS_HEADER_SET_OPCODE(q, QUERY); + if (rd) { + DNS_HEADER_SET_RD(q, 1); + } + else { + DNS_HEADER_SET_RD(q, 0); + } + DNS_HEADER_SET_QDCOUNT(q, 1); + + /* A name of "." is a screw case for the loop below, so adjust it. */ + if (strcmp(name, ".") == 0) + name++; + + /* Start writing out the name after the header. */ + q += HFIXEDSZ; + while (*name) + { + if (*name == '.') + return ARES_EBADNAME; + + /* Count the number of bytes in this label. */ + len = 0; + for (p = name; *p && *p != '.'; p++) + { + if (*p == '\\' && *(p + 1) != 0) + p++; + len++; + } + if (len > MAXLABEL) + return ARES_EBADNAME; + + /* Encode the length and copy the data. */ + *q++ = (unsigned char)len; + for (p = name; *p && *p != '.'; p++) + { + if (*p == '\\' && *(p + 1) != 0) + p++; + *q++ = *p; + } + + /* Go to the next label and repeat, unless we hit the end. */ + if (!*p) + break; + name = p + 1; + } + + /* Add the zero-length label at the end. */ + *q++ = 0; + + /* Finish off the question with the type and class. */ + DNS_QUESTION_SET_TYPE(q, type); + DNS_QUESTION_SET_CLASS(q, dnsclass); + + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares_nowarn.c b/deps/c-ares/ares_nowarn.c new file mode 100644 index 00000000000..91d0a5f205c --- /dev/null +++ b/deps/c-ares/ares_nowarn.c @@ -0,0 +1,53 @@ +/* $Id$ */ + +/* Copyright (C) 2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +#include "ares_setup.h" + +#include "ares_nowarn.h" + +#if (SIZEOF_INT == 2) +# define CARES_MASK_SINT 0x7FFF +# define CARES_MASK_UINT 0xFFFF +#elif (SIZEOF_INT == 4) +# define CARES_MASK_SINT 0x7FFFFFFF +# define CARES_MASK_UINT 0xFFFFFFFF +#elif (SIZEOF_INT == 8) +# define CARES_MASK_SINT 0x7FFFFFFFFFFFFFFF +# define CARES_MASK_UINT 0xFFFFFFFFFFFFFFFF +#elif (SIZEOF_INT == 16) +# define CARES_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +# define CARES_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +#endif + +/* +** size_t to signed int +*/ + +int aresx_uztosi(size_t uznum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + return (int)(uznum & (size_t) CARES_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} diff --git a/deps/c-ares/ares_nowarn.h b/deps/c-ares/ares_nowarn.h new file mode 100644 index 00000000000..0b7181bd469 --- /dev/null +++ b/deps/c-ares/ares_nowarn.h @@ -0,0 +1,23 @@ +#ifndef HEADER_CARES_NOWARN_H +#define HEADER_CARES_NOWARN_H + +/* $Id$ */ + +/* Copyright (C) 2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +int aresx_uztosi(size_t uznum); + +#endif /* HEADER_CARES_NOWARN_H */ diff --git a/deps/c-ares/ares_options.c b/deps/c-ares/ares_options.c new file mode 100644 index 00000000000..0c879740b2a --- /dev/null +++ b/deps/c-ares/ares_options.c @@ -0,0 +1,128 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2008-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +#include "ares_setup.h" + +#include "ares.h" +#include "ares_data.h" +#include "ares_private.h" + + +int ares_get_servers(ares_channel channel, + struct ares_addr_node **servers) +{ + struct ares_addr_node *srvr_head = NULL; + struct ares_addr_node *srvr_last = NULL; + struct ares_addr_node *srvr_curr; + int status = ARES_SUCCESS; + int i; + + if (!channel) + return ARES_ENODATA; + + for (i = 0; i < channel->nservers; i++) + { + /* Allocate storage for this server node appending it to the list */ + srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE); + if (!srvr_curr) + { + status = ARES_ENOMEM; + break; + } + if (srvr_last) + { + srvr_last->next = srvr_curr; + } + else + { + srvr_head = srvr_curr; + } + srvr_last = srvr_curr; + + /* Fill this server node data */ + srvr_curr->family = channel->servers[i].addr.family; + if (srvr_curr->family == AF_INET) + memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4, + sizeof(srvr_curr->addrV4)); + else + memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6, + sizeof(srvr_curr->addrV6)); + } + + if (status != ARES_SUCCESS) + { + if (srvr_head) + { + ares_free_data(srvr_head); + srvr_head = NULL; + } + } + + *servers = srvr_head; + + return status; +} + + +int ares_set_servers(ares_channel channel, + struct ares_addr_node *servers) +{ + struct ares_addr_node *srvr; + int num_srvrs = 0; + int i; + + if (ares_library_initialized() != ARES_SUCCESS) + return ARES_ENOTINITIALIZED; + + if (!channel) + return ARES_ENODATA; + + ares__destroy_servers_state(channel); + + for (srvr = servers; srvr; srvr = srvr->next) + { + num_srvrs++; + } + + if (num_srvrs > 0) + { + /* Allocate storage for servers state */ + channel->servers = malloc(num_srvrs * sizeof(struct server_state)); + if (!channel->servers) + { + return ARES_ENOMEM; + } + channel->nservers = num_srvrs; + /* Fill servers state address data */ + for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next) + { + channel->servers[i].addr.family = srvr->family; + if (srvr->family == AF_INET) + memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4, + sizeof(srvr->addrV4)); + else + memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6, + sizeof(srvr->addrV6)); + } + /* Initialize servers state remaining data */ + ares__init_servers_state(channel); + } + + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares_parse_a_reply.c b/deps/c-ares/ares_parse_a_reply.c new file mode 100644 index 00000000000..a6ed7dd2f05 --- /dev/null +++ b/deps/c-ares/ares_parse_a_reply.c @@ -0,0 +1,257 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#ifdef HAVE_LIMITS_H +# include +#endif + +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +int ares_parse_a_reply(const unsigned char *abuf, int alen, + struct hostent **host, + struct ares_addrttl *addrttls, int *naddrttls) +{ + unsigned int qdcount, ancount; + int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs; + int cname_ttl = INT_MAX; /* the TTL imposed by the CNAME chain */ + int naliases; + long len; + const unsigned char *aptr; + char *hostname, *rr_name, *rr_data, **aliases; + struct in_addr *addrs; + struct hostent *hostent; + const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0; + + /* Set *host to NULL for all failure cases. */ + if (host) + *host = NULL; + /* Same with *naddrttls. */ + if (naddrttls) + *naddrttls = 0; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + if (qdcount != 1) + return ARES_EBADRESP; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free(hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + if (host) + { + /* Allocate addresses and aliases; ancount gives an upper bound for + both. */ + addrs = malloc(ancount * sizeof(struct in_addr)); + if (!addrs) + { + free(hostname); + return ARES_ENOMEM; + } + aliases = malloc((ancount + 1) * sizeof(char *)); + if (!aliases) + { + free(hostname); + free(addrs); + return ARES_ENOMEM; + } + } + else + { + addrs = NULL; + aliases = NULL; + } + + naddrs = 0; + naliases = 0; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < (int)ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + break; + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE(aptr); + rr_class = DNS_RR_CLASS(aptr); + rr_len = DNS_RR_LEN(aptr); + rr_ttl = DNS_RR_TTL(aptr); + aptr += RRFIXEDSZ; + + if (rr_class == C_IN && rr_type == T_A + && rr_len == sizeof(struct in_addr) + && strcasecmp(rr_name, hostname) == 0) + { + if (addrs) + { + if (aptr + sizeof(struct in_addr) > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + memcpy(&addrs[naddrs], aptr, sizeof(struct in_addr)); + } + if (naddrs < max_addr_ttls) + { + struct ares_addrttl * const at = &addrttls[naddrs]; + if (aptr + sizeof(struct in_addr) > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + memcpy(&at->ipaddr, aptr, sizeof(struct in_addr)); + at->ttl = rr_ttl; + } + naddrs++; + status = ARES_SUCCESS; + } + + if (rr_class == C_IN && rr_type == T_CNAME) + { + /* Record the RR name as an alias. */ + if (aliases) + aliases[naliases] = rr_name; + else + free(rr_name); + naliases++; + + /* Decode the RR data and replace the hostname with it. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, + &len); + if (status != ARES_SUCCESS) + break; + free(hostname); + hostname = rr_data; + + /* Take the min of the TTLs we see in the CNAME chain. */ + if (cname_ttl > rr_ttl) + cname_ttl = rr_ttl; + } + else + free(rr_name); + + aptr += rr_len; + if (aptr > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + } + + if (status == ARES_SUCCESS && naddrs == 0) + status = ARES_ENODATA; + if (status == ARES_SUCCESS) + { + /* We got our answer. */ + if (naddrttls) + { + const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls; + for (i = 0; i < n; i++) + { + /* Ensure that each A TTL is no larger than the CNAME TTL. */ + if (addrttls[i].ttl > cname_ttl) + addrttls[i].ttl = cname_ttl; + } + *naddrttls = n; + } + if (aliases) + aliases[naliases] = NULL; + if (host) + { + /* Allocate memory to build the host entry. */ + hostent = malloc(sizeof(struct hostent)); + if (hostent) + { + hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *)); + if (hostent->h_addr_list) + { + /* Fill in the hostent and return successfully. */ + hostent->h_name = hostname; + hostent->h_aliases = aliases; + hostent->h_addrtype = AF_INET; + hostent->h_length = sizeof(struct in_addr); + for (i = 0; i < naddrs; i++) + hostent->h_addr_list[i] = (char *) &addrs[i]; + hostent->h_addr_list[naddrs] = NULL; + *host = hostent; + return ARES_SUCCESS; + } + free(hostent); + } + status = ARES_ENOMEM; + } + } + if (aliases) + { + for (i = 0; i < naliases; i++) + free(aliases[i]); + free(aliases); + } + free(addrs); + free(hostname); + return status; +} diff --git a/deps/c-ares/ares_parse_aaaa_reply.c b/deps/c-ares/ares_parse_aaaa_reply.c new file mode 100644 index 00000000000..8c2843f472e --- /dev/null +++ b/deps/c-ares/ares_parse_aaaa_reply.c @@ -0,0 +1,257 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright 2005 Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#ifdef HAVE_LIMITS_H +# include +#endif + +#include "ares.h" +#include "ares_dns.h" +#include "inet_net_pton.h" +#include "ares_private.h" + +int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, + struct hostent **host, struct ares_addr6ttl *addrttls, + int *naddrttls) +{ + unsigned int qdcount, ancount; + int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs; + int cname_ttl = INT_MAX; /* the TTL imposed by the CNAME chain */ + int naliases; + long len; + const unsigned char *aptr; + char *hostname, *rr_name, *rr_data, **aliases; + struct ares_in6_addr *addrs; + struct hostent *hostent; + const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0; + + /* Set *host to NULL for all failure cases. */ + if (host) + *host = NULL; + /* Same with *naddrttls. */ + if (naddrttls) + *naddrttls = 0; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + if (qdcount != 1) + return ARES_EBADRESP; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free(hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Allocate addresses and aliases; ancount gives an upper bound for both. */ + if (host) + { + addrs = malloc(ancount * sizeof(struct ares_in6_addr)); + if (!addrs) + { + free(hostname); + return ARES_ENOMEM; + } + aliases = malloc((ancount + 1) * sizeof(char *)); + if (!aliases) + { + free(hostname); + free(addrs); + return ARES_ENOMEM; + } + } + else + { + addrs = NULL; + aliases = NULL; + } + naddrs = 0; + naliases = 0; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < (int)ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + break; + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE(aptr); + rr_class = DNS_RR_CLASS(aptr); + rr_len = DNS_RR_LEN(aptr); + rr_ttl = DNS_RR_TTL(aptr); + aptr += RRFIXEDSZ; + + if (rr_class == C_IN && rr_type == T_AAAA + && rr_len == sizeof(struct ares_in6_addr) + && strcasecmp(rr_name, hostname) == 0) + { + if (addrs) + { + if (aptr + sizeof(struct ares_in6_addr) > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr)); + } + if (naddrs < max_addr_ttls) + { + struct ares_addr6ttl * const at = &addrttls[naddrs]; + if (aptr + sizeof(struct ares_in6_addr) > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + memcpy(&at->ip6addr, aptr, sizeof(struct ares_in6_addr)); + at->ttl = rr_ttl; + } + naddrs++; + status = ARES_SUCCESS; + } + + if (rr_class == C_IN && rr_type == T_CNAME) + { + /* Record the RR name as an alias. */ + if (aliases) + aliases[naliases] = rr_name; + else + free(rr_name); + naliases++; + + /* Decode the RR data and replace the hostname with it. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, + &len); + if (status != ARES_SUCCESS) + break; + free(hostname); + hostname = rr_data; + + /* Take the min of the TTLs we see in the CNAME chain. */ + if (cname_ttl > rr_ttl) + cname_ttl = rr_ttl; + } + else + free(rr_name); + + aptr += rr_len; + if (aptr > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + } + + if (status == ARES_SUCCESS && naddrs == 0) + status = ARES_ENODATA; + if (status == ARES_SUCCESS) + { + /* We got our answer. */ + if (naddrttls) + { + const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls; + for (i = 0; i < n; i++) + { + /* Ensure that each A TTL is no larger than the CNAME TTL. */ + if (addrttls[i].ttl > cname_ttl) + addrttls[i].ttl = cname_ttl; + } + *naddrttls = n; + } + if (aliases) + aliases[naliases] = NULL; + if (host) + { + /* Allocate memory to build the host entry. */ + hostent = malloc(sizeof(struct hostent)); + if (hostent) + { + hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *)); + if (hostent->h_addr_list) + { + /* Fill in the hostent and return successfully. */ + hostent->h_name = hostname; + hostent->h_aliases = aliases; + hostent->h_addrtype = AF_INET6; + hostent->h_length = sizeof(struct ares_in6_addr); + for (i = 0; i < naddrs; i++) + hostent->h_addr_list[i] = (char *) &addrs[i]; + hostent->h_addr_list[naddrs] = NULL; + *host = hostent; + return ARES_SUCCESS; + } + free(hostent); + } + status = ARES_ENOMEM; + } + } + if (aliases) + { + for (i = 0; i < naliases; i++) + free(aliases[i]); + free(aliases); + } + free(addrs); + free(hostname); + return status; +} diff --git a/deps/c-ares/ares_parse_ns_reply.c b/deps/c-ares/ares_parse_ns_reply.c new file mode 100644 index 00000000000..25c632994a5 --- /dev/null +++ b/deps/c-ares/ares_parse_ns_reply.c @@ -0,0 +1,182 @@ +/* $Id */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * ares_parse_ns_reply created by Vlad Dinulescu + * on behalf of AVIRA Gmbh - http://www.avira.com + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +int ares_parse_ns_reply( const unsigned char* abuf, int alen, + struct hostent** host ) +{ + unsigned int qdcount, ancount; + int status, i, rr_type, rr_class, rr_len; + int nameservers_num; + long len; + const unsigned char *aptr; + char* hostname, *rr_name, *rr_data, **nameservers; + struct hostent *hostent; + + /* Set *host to NULL for all failure cases. */ + *host = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if ( alen < HFIXEDSZ ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT( abuf ); + ancount = DNS_HEADER_ANCOUNT( abuf ); + if ( qdcount != 1 ) + return ARES_EBADRESP; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len); + if ( status != ARES_SUCCESS ) + return status; + if ( aptr + len + QFIXEDSZ > abuf + alen ) + { + free( hostname ); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Allocate nameservers array; ancount gives an upper bound */ + nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) ); + if ( !nameservers ) + { + free( hostname ); + return ARES_ENOMEM; + } + nameservers_num = 0; + + /* Examine each answer resource record (RR) in turn. */ + for ( i = 0; i < ( int ) ancount; i++ ) + { + /* Decode the RR up to the data field. */ + status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len ); + if ( status != ARES_SUCCESS ) + break; + aptr += len; + if ( aptr + RRFIXEDSZ > abuf + alen ) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE( aptr ); + rr_class = DNS_RR_CLASS( aptr ); + rr_len = DNS_RR_LEN( aptr ); + aptr += RRFIXEDSZ; + + if ( rr_class == C_IN && rr_type == T_NS ) + { + /* Decode the RR data and add it to the nameservers list */ + status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data, + &len); + if ( status != ARES_SUCCESS ) + { + break; + } + + nameservers[nameservers_num] = malloc(strlen(rr_data)+1); + + if (nameservers[nameservers_num]==NULL) + { + free(rr_name); + free(rr_data); + status=ARES_ENOMEM; + break; + } + strcpy(nameservers[nameservers_num],rr_data); + free(rr_data); + + nameservers_num++; + } + + free( rr_name ); + + aptr += rr_len; + if ( aptr > abuf + alen ) + { + status = ARES_EBADRESP; + break; + } + } + + if ( status == ARES_SUCCESS && nameservers_num == 0 ) + { + status = ARES_ENODATA; + } + if ( status == ARES_SUCCESS ) + { + /* We got our answer. Allocate memory to build the host entry. */ + nameservers[nameservers_num] = NULL; + hostent = malloc( sizeof( struct hostent ) ); + if ( hostent ) + { + hostent->h_addr_list = malloc( 1 * sizeof( char * ) ); + if ( hostent->h_addr_list ) + { + /* Fill in the hostent and return successfully. */ + hostent->h_name = hostname; + hostent->h_aliases = nameservers; + hostent->h_addrtype = AF_INET; + hostent->h_length = sizeof( struct in_addr ); + hostent->h_addr_list[0] = NULL; + *host = hostent; + return ARES_SUCCESS; + } + free( hostent ); + } + status = ARES_ENOMEM; + } + for ( i = 0; i < nameservers_num; i++ ) + free( nameservers[i] ); + free( nameservers ); + free( hostname ); + return status; +} diff --git a/deps/c-ares/ares_parse_ptr_reply.c b/deps/c-ares/ares_parse_ptr_reply.c new file mode 100644 index 00000000000..9923a9da0e4 --- /dev/null +++ b/deps/c-ares/ares_parse_ptr_reply.c @@ -0,0 +1,209 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, + int addrlen, int family, struct hostent **host) +{ + unsigned int qdcount, ancount; + int status, i, rr_type, rr_class, rr_len; + long len; + const unsigned char *aptr; + char *ptrname, *hostname, *rr_name, *rr_data; + struct hostent *hostent; + int aliascnt = 0; + int alias_alloc = 8; + char ** aliases; + + /* Set *host to NULL for all failure cases. */ + *host = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + if (qdcount != 1) + return ARES_EBADRESP; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len); + if (status != ARES_SUCCESS) + return status; + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free(ptrname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Examine each answer resource record (RR) in turn. */ + hostname = NULL; + aliases = malloc(alias_alloc * sizeof(char *)); + if (!aliases) + { + free(ptrname); + return ARES_ENOMEM; + } + for (i = 0; i < (int)ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + break; + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE(aptr); + rr_class = DNS_RR_CLASS(aptr); + rr_len = DNS_RR_LEN(aptr); + aptr += RRFIXEDSZ; + + if (rr_class == C_IN && rr_type == T_PTR + && strcasecmp(rr_name, ptrname) == 0) + { + /* Decode the RR data and set hostname to it. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, + &len); + if (status != ARES_SUCCESS) + break; + if (hostname) + free(hostname); + hostname = rr_data; + aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char *)); + if (!aliases[aliascnt]) + { + status = ARES_ENOMEM; + break; + } + strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1); + aliascnt++; + if (aliascnt >= alias_alloc) { + char **ptr; + alias_alloc *= 2; + ptr = realloc(aliases, alias_alloc * sizeof(char *)); + if(!ptr) { + status = ARES_ENOMEM; + break; + } + aliases = ptr; + } + } + + if (rr_class == C_IN && rr_type == T_CNAME) + { + /* Decode the RR data and replace ptrname with it. */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, + &len); + if (status != ARES_SUCCESS) + break; + free(ptrname); + ptrname = rr_data; + } + + free(rr_name); + aptr += rr_len; + if (aptr > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + } + + if (status == ARES_SUCCESS && !hostname) + status = ARES_ENODATA; + if (status == ARES_SUCCESS) + { + /* We got our answer. Allocate memory to build the host entry. */ + hostent = malloc(sizeof(struct hostent)); + if (hostent) + { + hostent->h_addr_list = malloc(2 * sizeof(char *)); + if (hostent->h_addr_list) + { + hostent->h_addr_list[0] = malloc(addrlen); + if (hostent->h_addr_list[0]) + { + hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *)); + if (hostent->h_aliases) + { + /* Fill in the hostent and return successfully. */ + hostent->h_name = hostname; + for (i=0 ; ih_aliases[i] = aliases[i]; + hostent->h_aliases[aliascnt] = NULL; + hostent->h_addrtype = family; + hostent->h_length = addrlen; + memcpy(hostent->h_addr_list[0], addr, addrlen); + hostent->h_addr_list[1] = NULL; + *host = hostent; + free(aliases); + free(ptrname); + return ARES_SUCCESS; + } + free(hostent->h_addr_list[0]); + } + free(hostent->h_addr_list); + } + free(hostent); + } + status = ARES_ENOMEM; + } + for (i=0 ; i + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_data.h" +#include "ares_private.h" + +/* AIX portability check */ +#ifndef T_SRV +# define T_SRV 33 /* server selection */ +#endif + +int +ares_parse_srv_reply (const unsigned char *abuf, int alen, + struct ares_srv_reply **srv_out) +{ + unsigned int qdcount, ancount, i; + const unsigned char *aptr, *vptr; + int status, rr_type, rr_class, rr_len; + long len; + char *hostname = NULL, *rr_name = NULL; + struct ares_srv_reply *srv_head = NULL; + struct ares_srv_reply *srv_last = NULL; + struct ares_srv_reply *srv_curr; + + /* Set *srv_out to NULL for all failure cases. */ + *srv_out = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT (abuf); + ancount = DNS_HEADER_ANCOUNT (abuf); + if (qdcount != 1) + return ARES_EBADRESP; + if (ancount == 0) + return ARES_ENODATA; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares_expand_name (aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free (hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + { + break; + } + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE (aptr); + rr_class = DNS_RR_CLASS (aptr); + rr_len = DNS_RR_LEN (aptr); + aptr += RRFIXEDSZ; + + /* Check if we are really looking at a SRV record */ + if (rr_class == C_IN && rr_type == T_SRV) + { + /* parse the SRV record itself */ + if (rr_len < 6) + { + status = ARES_EBADRESP; + break; + } + + /* Allocate storage for this SRV answer appending it to the list */ + srv_curr = ares_malloc_data(ARES_DATATYPE_SRV_REPLY); + if (!srv_curr) + { + status = ARES_ENOMEM; + break; + } + if (srv_last) + { + srv_last->next = srv_curr; + } + else + { + srv_head = srv_curr; + } + srv_last = srv_curr; + + vptr = aptr; + srv_curr->priority = ntohs (*((unsigned short *)vptr)); + vptr += sizeof(unsigned short); + srv_curr->weight = ntohs (*((unsigned short *)vptr)); + vptr += sizeof(unsigned short); + srv_curr->port = ntohs (*((unsigned short *)vptr)); + vptr += sizeof(unsigned short); + + status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len); + if (status != ARES_SUCCESS) + break; + } + + /* Don't lose memory in the next iteration */ + free (rr_name); + rr_name = NULL; + + /* Move on to the next record */ + aptr += rr_len; + } + + if (hostname) + free (hostname); + if (rr_name) + free (rr_name); + + /* clean up on error */ + if (status != ARES_SUCCESS) + { + if (srv_head) + ares_free_data (srv_head); + return status; + } + + /* everything looks fine, return the data */ + *srv_out = srv_head; + + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares_parse_txt_reply.c b/deps/c-ares/ares_parse_txt_reply.c new file mode 100644 index 00000000000..8e24e63b78d --- /dev/null +++ b/deps/c-ares/ares_parse_txt_reply.c @@ -0,0 +1,202 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2009 by Jakub Hrozek + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "ares.h" +#include "ares_dns.h" +#include "ares_data.h" +#include "ares_private.h" + +int +ares_parse_txt_reply (const unsigned char *abuf, int alen, + struct ares_txt_reply **txt_out) +{ + size_t substr_len, str_len; + unsigned int qdcount, ancount, i; + const unsigned char *aptr; + const unsigned char *strptr; + int status, rr_type, rr_class, rr_len; + long len; + char *hostname = NULL, *rr_name = NULL; + struct ares_txt_reply *txt_head = NULL; + struct ares_txt_reply *txt_last = NULL; + struct ares_txt_reply *txt_curr; + + /* Set *txt_out to NULL for all failure cases. */ + *txt_out = NULL; + + /* Give up if abuf doesn't have room for a header. */ + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* Fetch the question and answer count from the header. */ + qdcount = DNS_HEADER_QDCOUNT (abuf); + ancount = DNS_HEADER_ANCOUNT (abuf); + if (qdcount != 1) + return ARES_EBADRESP; + if (ancount == 0) + return ARES_ENODATA; + + /* Expand the name from the question, and skip past the question. */ + aptr = abuf + HFIXEDSZ; + status = ares_expand_name (aptr, abuf, alen, &hostname, &len); + if (status != ARES_SUCCESS) + return status; + + if (aptr + len + QFIXEDSZ > abuf + alen) + { + free (hostname); + return ARES_EBADRESP; + } + aptr += len + QFIXEDSZ; + + /* Examine each answer resource record (RR) in turn. */ + for (i = 0; i < ancount; i++) + { + /* Decode the RR up to the data field. */ + status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + { + break; + } + aptr += len; + if (aptr + RRFIXEDSZ > abuf + alen) + { + status = ARES_EBADRESP; + break; + } + rr_type = DNS_RR_TYPE (aptr); + rr_class = DNS_RR_CLASS (aptr); + rr_len = DNS_RR_LEN (aptr); + aptr += RRFIXEDSZ; + + /* Check if we are really looking at a TXT record */ + if (rr_class == C_IN && rr_type == T_TXT) + { + /* Allocate storage for this TXT answer appending it to the list */ + txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY); + if (!txt_curr) + { + status = ARES_ENOMEM; + break; + } + if (txt_last) + { + txt_last->next = txt_curr; + } + else + { + txt_head = txt_curr; + } + txt_last = txt_curr; + + /* + * There may be multiple substrings in a single TXT record. Each + * substring may be up to 255 characters in length, with a + * "length byte" indicating the size of the substring payload. + * RDATA contains both the length-bytes and payloads of all + * substrings contained therein. + */ + + /* Compute total length to allow a single memory allocation */ + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + txt_curr->length += substr_len; + strptr += substr_len + 1; + } + + /* Including null byte */ + txt_curr->txt = malloc (txt_curr->length + 1); + if (txt_curr->txt == NULL) + { + status = ARES_ENOMEM; + break; + } + + /* Step through the list of substrings, concatenating them */ + str_len = 0; + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + strptr++; + memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len); + str_len += substr_len; + strptr += substr_len; + } + /* Make sure we NULL-terminate */ + *((char *) txt_curr->txt + txt_curr->length) = '\0'; + } + + /* Don't lose memory in the next iteration */ + free (rr_name); + rr_name = NULL; + + /* Move on to the next record */ + aptr += rr_len; + } + + if (hostname) + free (hostname); + if (rr_name) + free (rr_name); + + /* clean up on error */ + if (status != ARES_SUCCESS) + { + if (txt_head) + ares_free_data (txt_head); + return status; + } + + /* everything looks fine, return the data */ + *txt_out = txt_head; + + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares_private.h b/deps/c-ares/ares_private.h new file mode 100644 index 00000000000..2766d191646 --- /dev/null +++ b/deps/c-ares/ares_private.h @@ -0,0 +1,345 @@ +#ifndef __ARES_PRIVATE_H +#define __ARES_PRIVATE_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2004-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef WATT32 +#include +#include +#define writev(s,v,c) writev_s(s,v,c) +#define HAVE_WRITEV 1 +#endif + +#ifdef NETWARE +#include +#endif + +#define DEFAULT_TIMEOUT 5000 /* milliseconds */ +#define DEFAULT_TRIES 4 +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#if defined(WIN32) && !defined(WATT32) + +#define IS_NT() ((int)GetVersion() > 0) +#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" +#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" +#define NAMESERVER "NameServer" +#define DHCPNAMESERVER "DhcpNameServer" +#define DATABASEPATH "DatabasePath" +#define WIN_PATH_HOSTS "\\hosts" + +#elif defined(WATT32) + +#define PATH_RESOLV_CONF "/dev/ENV/etc/resolv.conf" + +#elif defined(NETWARE) + +#define PATH_RESOLV_CONF "sys:/etc/resolv.cfg" +#define PATH_HOSTS "sys:/etc/hosts" + +#elif defined(__riscos__) + +#define PATH_HOSTS "InetDBase:Hosts" + +#else + +#define PATH_RESOLV_CONF "/etc/resolv.conf" +#ifdef ETC_INET +#define PATH_HOSTS "/etc/inet/hosts" +#else +#define PATH_HOSTS "/etc/hosts" +#endif + +#endif + +#define ARES_ID_KEY_LEN 31 + +#include "ares_ipv6.h" +#include "ares_llist.h" + +#ifndef HAVE_STRDUP +# include "ares_strdup.h" +# define strdup(ptr) ares_strdup(ptr) +#endif + +#ifndef HAVE_STRCASECMP +# include "ares_strcasecmp.h" +# define strcasecmp(p1,p2) ares_strcasecmp(p1,p2) +#endif + +#ifndef HAVE_STRNCASECMP +# include "ares_strcasecmp.h" +# define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n) +#endif + +#ifndef HAVE_WRITEV +# include "ares_writev.h" +# define writev(s,ptr,cnt) ares_writev(s,ptr,cnt) +#endif + +struct ares_addr { + int family; + union { + struct in_addr addr4; + struct ares_in6_addr addr6; + } addr; +}; +#define addrV4 addr.addr4 +#define addrV6 addr.addr6 + +struct query; + +struct send_request { + /* Remaining data to send */ + const unsigned char *data; + size_t len; + + /* The query for which we're sending this data */ + struct query* owner_query; + /* The buffer we're using, if we have our own copy of the packet */ + unsigned char *data_storage; + + /* Next request in queue */ + struct send_request *next; +}; + +struct server_state { + struct ares_addr addr; + ares_socket_t udp_socket; + ares_socket_t tcp_socket; + + /* Mini-buffer for reading the length word */ + unsigned char tcp_lenbuf[2]; + int tcp_lenbuf_pos; + int tcp_length; + + /* Buffer for reading actual TCP data */ + unsigned char *tcp_buffer; + int tcp_buffer_pos; + + /* TCP output queue */ + struct send_request *qhead; + struct send_request *qtail; + + /* Which incarnation of this connection is this? We don't want to + * retransmit requests into the very same socket, but if the server + * closes on us and we re-open the connection, then we do want to + * re-send. */ + int tcp_connection_generation; + + /* Circular, doubly-linked list of outstanding queries to this server */ + struct list_node queries_to_server; + + /* Link back to owning channel */ + ares_channel channel; + + /* Is this server broken? We mark connections as broken when a + * request that is queued for sending times out. + */ + int is_broken; +}; + +/* State to represent a DNS query */ +struct query { + /* Query ID from qbuf, for faster lookup, and current timeout */ + unsigned short qid; + struct timeval timeout; + + /* + * Links for the doubly-linked lists in which we insert a query. + * These circular, doubly-linked lists that are hash-bucketed based + * the attributes we care about, help making most important + * operations O(1). + */ + struct list_node queries_by_qid; /* hopefully in same cache line as qid */ + struct list_node queries_by_timeout; + struct list_node queries_to_server; + struct list_node all_queries; + + /* Query buf with length at beginning, for TCP transmission */ + unsigned char *tcpbuf; + int tcplen; + + /* Arguments passed to ares_send() (qbuf points into tcpbuf) */ + const unsigned char *qbuf; + int qlen; + ares_callback callback; + void *arg; + + /* Query status */ + int try; /* Number of times we tried this query already. */ + int server; /* Server this query has last been sent to. */ + struct query_server_info *server_info; /* per-server state */ + int using_tcp; + int error_status; + int timeouts; /* number of timeouts we saw for this request */ +}; + +/* Per-server state for a query */ +struct query_server_info { + int skip_server; /* should we skip server, due to errors, etc? */ + int tcp_connection_generation; /* into which TCP connection did we send? */ +}; + +/* An IP address pattern; matches an IP address X if X & mask == addr */ +#define PATTERN_MASK 0x1 +#define PATTERN_CIDR 0x2 + +struct apattern { + union + { + struct in_addr addr4; + struct ares_in6_addr addr6; + } addr; + union + { + struct in_addr addr4; + struct ares_in6_addr addr6; + unsigned short bits; + } mask; + int family; + unsigned short type; +}; + +typedef struct rc4_key +{ + unsigned char state[256]; + unsigned char x; + unsigned char y; +} rc4_key; + +struct ares_channeldata { + /* Configuration data */ + int flags; + int timeout; /* in milliseconds */ + int tries; + int ndots; + int rotate; /* if true, all servers specified are used */ + int udp_port; + int tcp_port; + int socket_send_buffer_size; + int socket_receive_buffer_size; + char **domains; + int ndomains; + struct apattern *sortlist; + int nsort; + char *lookups; + + int optmask; /* the option bitfield passed in at init time */ + + /* Server addresses and communications state */ + struct server_state *servers; + int nservers; + + /* ID to use for next query */ + unsigned short next_id; + /* key to use when generating new ids */ + rc4_key id_key; + + /* Generation number to use for the next TCP socket open/close */ + int tcp_connection_generation; + + /* The time at which we last called process_timeouts(). Uses integer seconds + just to draw the line somewhere. */ + time_t last_timeout_processed; + + /* Last server we sent a query to. */ + int last_server; + + /* Circular, doubly-linked list of queries, bucketed various ways.... */ + /* All active queries in a single list: */ + struct list_node all_queries; + /* Queries bucketed by qid, for quickly dispatching DNS responses: */ +#define ARES_QID_TABLE_SIZE 2048 + struct list_node queries_by_qid[ARES_QID_TABLE_SIZE]; + /* Queries bucketed by timeout, for quickly handling timeouts: */ +#define ARES_TIMEOUT_TABLE_SIZE 1024 + struct list_node queries_by_timeout[ARES_TIMEOUT_TABLE_SIZE]; + + ares_sock_state_cb sock_state_cb; + void *sock_state_cb_data; + + ares_sock_create_callback sock_create_cb; + void *sock_create_cb_data; +}; + +/* return true if now is exactly check time or later */ +int ares__timedout(struct timeval *now, + struct timeval *check); +/* add the specific number of milliseconds to the time in the first argument */ +int ares__timeadd(struct timeval *now, + int millisecs); +/* return time offset between now and (future) check, in milliseconds */ +long ares__timeoffset(struct timeval *now, + struct timeval *check); +/* returns ARES_SUCCESS if library has been initialized */ +int ares_library_initialized(void); +void ares__rc4(rc4_key* key,unsigned char *buffer_ptr, int buffer_len); +void ares__send_query(ares_channel channel, struct query *query, + struct timeval *now); +void ares__close_sockets(ares_channel channel, struct server_state *server); +int ares__get_hostent(FILE *fp, int family, struct hostent **host); +int ares__read_line(FILE *fp, char **buf, size_t *bufsize); +void ares__free_query(struct query *query); +unsigned short ares__generate_new_id(rc4_key* key); +struct timeval ares__tvnow(void); +int ares__expand_name_for_response(const unsigned char *encoded, + const unsigned char *abuf, int alen, + char **s, long *enclen); +void ares__init_servers_state(ares_channel channel); +void ares__destroy_servers_state(ares_channel channel); +#if 0 /* Not used */ +long ares__tvdiff(struct timeval t1, struct timeval t2); +#endif + +#define ARES_SWAP_BYTE(a,b) \ + { unsigned char swapByte = *(a); *(a) = *(b); *(b) = swapByte; } + +#define SOCK_STATE_CALLBACK(c, s, r, w) \ + do { \ + if ((c)->sock_state_cb) \ + (c)->sock_state_cb((c)->sock_state_cb_data, (s), (r), (w)); \ + } while (0) + +#ifdef CURLDEBUG +/* This is low-level hard-hacking memory leak tracking and similar. Using the + libcurl lowlevel code from within library is ugly and only works when + c-ares is built and linked with a similarly curldebug-enabled libcurl, + but we do this anyway for convenience. */ +#include "../lib/memdebug.h" +#endif + +#endif /* __ARES_PRIVATE_H */ diff --git a/deps/c-ares/ares_process.c b/deps/c-ares/ares_process.c new file mode 100644 index 00000000000..ab0b79dc689 --- /dev/null +++ b/deps/c-ares/ares_process.c @@ -0,0 +1,1262 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2004-2010 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_UIO_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef NETWARE +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + + +static int try_again(int errnum); +static void write_tcp_data(ares_channel channel, fd_set *write_fds, + ares_socket_t write_fd, struct timeval *now); +static void read_tcp_data(ares_channel channel, fd_set *read_fds, + ares_socket_t read_fd, struct timeval *now); +static void read_udp_packets(ares_channel channel, fd_set *read_fds, + ares_socket_t read_fd, struct timeval *now); +static void advance_tcp_send_queue(ares_channel channel, int whichserver, + ssize_t num_bytes); +static void process_timeouts(ares_channel channel, struct timeval *now); +static void process_broken_connections(ares_channel channel, + struct timeval *now); +static void process_answer(ares_channel channel, unsigned char *abuf, + int alen, int whichserver, int tcp, + struct timeval *now); +static void handle_error(ares_channel channel, int whichserver, + struct timeval *now); +static void skip_server(ares_channel channel, struct query *query, + int whichserver); +static void next_server(ares_channel channel, struct query *query, + struct timeval *now); +static int configure_socket(ares_socket_t s, ares_channel channel); +static int open_tcp_socket(ares_channel channel, struct server_state *server); +static int open_udp_socket(ares_channel channel, struct server_state *server); +static int same_questions(const unsigned char *qbuf, int qlen, + const unsigned char *abuf, int alen); +static int same_address(struct sockaddr *sa, struct ares_addr *aa); +static void end_query(ares_channel channel, struct query *query, int status, + unsigned char *abuf, int alen); + +/* return true if now is exactly check time or later */ +int ares__timedout(struct timeval *now, + struct timeval *check) +{ + long secs = (now->tv_sec - check->tv_sec); + + if(secs > 0) + return 1; /* yes, timed out */ + if(secs < 0) + return 0; /* nope, not timed out */ + + /* if the full seconds were identical, check the sub second parts */ + return (now->tv_usec - check->tv_usec >= 0); +} + +/* add the specific number of milliseconds to the time in the first argument */ +int ares__timeadd(struct timeval *now, + int millisecs) +{ + now->tv_sec += millisecs/1000; + now->tv_usec += (millisecs%1000)*1000; + + if(now->tv_usec >= 1000000) { + ++(now->tv_sec); + now->tv_usec -= 1000000; + } + + return 0; +} + +/* return time offset between now and (future) check, in milliseconds */ +long ares__timeoffset(struct timeval *now, + struct timeval *check) +{ + return (check->tv_sec - now->tv_sec)*1000 + + (check->tv_usec - now->tv_usec)/1000; +} + + +/* + * generic process function + */ +static void processfds(ares_channel channel, + fd_set *read_fds, ares_socket_t read_fd, + fd_set *write_fds, ares_socket_t write_fd) +{ + struct timeval now = ares__tvnow(); + + write_tcp_data(channel, write_fds, write_fd, &now); + read_tcp_data(channel, read_fds, read_fd, &now); + read_udp_packets(channel, read_fds, read_fd, &now); + process_timeouts(channel, &now); + process_broken_connections(channel, &now); +} + +/* Something interesting happened on the wire, or there was a timeout. + * See what's up and respond accordingly. + */ +void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds) +{ + processfds(channel, read_fds, ARES_SOCKET_BAD, write_fds, ARES_SOCKET_BAD); +} + +/* Something interesting happened on the wire, or there was a timeout. + * See what's up and respond accordingly. + */ +void ares_process_fd(ares_channel channel, + ares_socket_t read_fd, /* use ARES_SOCKET_BAD or valid + file descriptors */ + ares_socket_t write_fd) +{ + processfds(channel, NULL, read_fd, NULL, write_fd); +} + + +/* Return 1 if the specified error number describes a readiness error, or 0 + * otherwise. This is mostly for HP-UX, which could return EAGAIN or + * EWOULDBLOCK. See this man page + * + * http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html? + * manpage=/usr/share/man/man2.Z/send.2 + */ +static int try_again(int errnum) +{ +#if !defined EWOULDBLOCK && !defined EAGAIN +#error "Neither EWOULDBLOCK nor EAGAIN defined" +#endif + switch (errnum) + { +#ifdef EWOULDBLOCK + case EWOULDBLOCK: + return 1; +#endif +#if defined EAGAIN && EAGAIN != EWOULDBLOCK + case EAGAIN: + return 1; +#endif + } + return 0; +} + +/* If any TCP sockets select true for writing, write out queued data + * we have for them. + */ +static void write_tcp_data(ares_channel channel, + fd_set *write_fds, + ares_socket_t write_fd, + struct timeval *now) +{ + struct server_state *server; + struct send_request *sendreq; + struct iovec *vec; + int i; + ssize_t scount; + ssize_t wcount; + size_t n; + + if(!write_fds && (write_fd == ARES_SOCKET_BAD)) + /* no possible action */ + return; + + for (i = 0; i < channel->nservers; i++) + { + /* Make sure server has data to send and is selected in write_fds or + write_fd. */ + server = &channel->servers[i]; + if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD || + server->is_broken) + continue; + + if(write_fds) { + if(!FD_ISSET(server->tcp_socket, write_fds)) + continue; + } + else { + if(server->tcp_socket != write_fd) + continue; + } + + if(write_fds) + /* If there's an error and we close this socket, then open + * another with the same fd to talk to another server, then we + * don't want to think that it was the new socket that was + * ready. This is not disastrous, but is likely to result in + * extra system calls and confusion. */ + FD_CLR(server->tcp_socket, write_fds); + + /* Count the number of send queue items. */ + n = 0; + for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) + n++; + + /* Allocate iovecs so we can send all our data at once. */ + vec = malloc(n * sizeof(struct iovec)); + if (vec) + { + /* Fill in the iovecs and send. */ + n = 0; + for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) + { + vec[n].iov_base = (char *) sendreq->data; + vec[n].iov_len = sendreq->len; + n++; + } + wcount = (ssize_t)writev(server->tcp_socket, vec, (int)n); + free(vec); + if (wcount < 0) + { + if (!try_again(SOCKERRNO)) + handle_error(channel, i, now); + continue; + } + + /* Advance the send queue by as many bytes as we sent. */ + advance_tcp_send_queue(channel, i, wcount); + } + else + { + /* Can't allocate iovecs; just send the first request. */ + sendreq = server->qhead; + + scount = swrite(server->tcp_socket, sendreq->data, sendreq->len); + if (scount < 0) + { + if (!try_again(SOCKERRNO)) + handle_error(channel, i, now); + continue; + } + + /* Advance the send queue by as many bytes as we sent. */ + advance_tcp_send_queue(channel, i, scount); + } + } +} + +/* Consume the given number of bytes from the head of the TCP send queue. */ +static void advance_tcp_send_queue(ares_channel channel, int whichserver, + ssize_t num_bytes) +{ + struct send_request *sendreq; + struct server_state *server = &channel->servers[whichserver]; + while (num_bytes > 0) + { + sendreq = server->qhead; + if ((size_t)num_bytes >= sendreq->len) + { + num_bytes -= sendreq->len; + server->qhead = sendreq->next; + if (server->qhead == NULL) + { + SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0); + server->qtail = NULL; + } + if (sendreq->data_storage != NULL) + free(sendreq->data_storage); + free(sendreq); + } + else + { + sendreq->data += num_bytes; + sendreq->len -= num_bytes; + num_bytes = 0; + } + } +} + +/* If any TCP socket selects true for reading, read some data, + * allocate a buffer if we finish reading the length word, and process + * a packet if we finish reading one. + */ +static void read_tcp_data(ares_channel channel, fd_set *read_fds, + ares_socket_t read_fd, struct timeval *now) +{ + struct server_state *server; + int i; + ssize_t count; + + if(!read_fds && (read_fd == ARES_SOCKET_BAD)) + /* no possible action */ + return; + + for (i = 0; i < channel->nservers; i++) + { + /* Make sure the server has a socket and is selected in read_fds. */ + server = &channel->servers[i]; + if (server->tcp_socket == ARES_SOCKET_BAD || server->is_broken) + continue; + + if(read_fds) { + if(!FD_ISSET(server->tcp_socket, read_fds)) + continue; + } + else { + if(server->tcp_socket != read_fd) + continue; + } + + if(read_fds) + /* If there's an error and we close this socket, then open + * another with the same fd to talk to another server, then we + * don't want to think that it was the new socket that was + * ready. This is not disastrous, but is likely to result in + * extra system calls and confusion. */ + FD_CLR(server->tcp_socket, read_fds); + + if (server->tcp_lenbuf_pos != 2) + { + /* We haven't yet read a length word, so read that (or + * what's left to read of it). + */ + count = sread(server->tcp_socket, + server->tcp_lenbuf + server->tcp_lenbuf_pos, + 2 - server->tcp_lenbuf_pos); + if (count <= 0) + { + if (!(count == -1 && try_again(SOCKERRNO))) + handle_error(channel, i, now); + continue; + } + + server->tcp_lenbuf_pos += (int)count; + if (server->tcp_lenbuf_pos == 2) + { + /* We finished reading the length word. Decode the + * length and allocate a buffer for the data. + */ + server->tcp_length = server->tcp_lenbuf[0] << 8 + | server->tcp_lenbuf[1]; + server->tcp_buffer = malloc(server->tcp_length); + if (!server->tcp_buffer) + handle_error(channel, i, now); + server->tcp_buffer_pos = 0; + } + } + else + { + /* Read data into the allocated buffer. */ + count = sread(server->tcp_socket, + server->tcp_buffer + server->tcp_buffer_pos, + server->tcp_length - server->tcp_buffer_pos); + if (count <= 0) + { + if (!(count == -1 && try_again(SOCKERRNO))) + handle_error(channel, i, now); + continue; + } + + server->tcp_buffer_pos += (int)count; + if (server->tcp_buffer_pos == server->tcp_length) + { + /* We finished reading this answer; process it and + * prepare to read another length word. + */ + process_answer(channel, server->tcp_buffer, server->tcp_length, + i, 1, now); + if (server->tcp_buffer) + free(server->tcp_buffer); + server->tcp_buffer = NULL; + server->tcp_lenbuf_pos = 0; + server->tcp_buffer_pos = 0; + } + } + } +} + +/* If any UDP sockets select true for reading, process them. */ +static void read_udp_packets(ares_channel channel, fd_set *read_fds, + ares_socket_t read_fd, struct timeval *now) +{ + struct server_state *server; + int i; + ssize_t count; + unsigned char buf[PACKETSZ + 1]; +#ifdef HAVE_RECVFROM + ares_socklen_t fromlen; + union { + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + } from; +#endif + + if(!read_fds && (read_fd == ARES_SOCKET_BAD)) + /* no possible action */ + return; + + for (i = 0; i < channel->nservers; i++) + { + /* Make sure the server has a socket and is selected in read_fds. */ + server = &channel->servers[i]; + + if (server->udp_socket == ARES_SOCKET_BAD || server->is_broken) + continue; + + if(read_fds) { + if(!FD_ISSET(server->udp_socket, read_fds)) + continue; + } + else { + if(server->udp_socket != read_fd) + continue; + } + + if(read_fds) + /* If there's an error and we close this socket, then open + * another with the same fd to talk to another server, then we + * don't want to think that it was the new socket that was + * ready. This is not disastrous, but is likely to result in + * extra system calls and confusion. */ + FD_CLR(server->udp_socket, read_fds); + + /* To reduce event loop overhead, read and process as many + * packets as we can. */ + do { +#ifdef HAVE_RECVFROM + if (server->addr.family == AF_INET) + fromlen = sizeof(from.sa4); + else + fromlen = sizeof(from.sa6); + count = (ssize_t)recvfrom(server->udp_socket, (void *)buf, sizeof(buf), + 0, (struct sockaddr *)&from, &fromlen); +#else + count = sread(server->udp_socket, buf, sizeof(buf)); +#endif + if (count == -1 && try_again(SOCKERRNO)) + continue; + else if (count <= 0) + handle_error(channel, i, now); +#ifdef HAVE_RECVFROM + else if (!same_address((struct sockaddr *)&from, &server->addr)) + /* The address the response comes from does not match + * the address we sent the request to. Someone may be + * attempting to perform a cache poisoning attack. */ + break; +#endif + else + process_answer(channel, buf, (int)count, i, 0, now); + } while (count > 0); + } +} + +/* If any queries have timed out, note the timeout and move them on. */ +static void process_timeouts(ares_channel channel, struct timeval *now) +{ + time_t t; /* the time of the timeouts we're processing */ + struct query *query; + struct list_node* list_head; + struct list_node* list_node; + + /* Process all the timeouts that have fired since the last time we + * processed timeouts. If things are going well, then we'll have + * hundreds/thousands of queries that fall into future buckets, and + * only a handful of requests that fall into the "now" bucket, so + * this should be quite quick. + */ + for (t = channel->last_timeout_processed; t <= now->tv_sec; t++) + { + list_head = &(channel->queries_by_timeout[t % ARES_TIMEOUT_TABLE_SIZE]); + for (list_node = list_head->next; list_node != list_head; ) + { + query = list_node->data; + list_node = list_node->next; /* in case the query gets deleted */ + if (query->timeout.tv_sec && ares__timedout(now, &query->timeout)) + { + query->error_status = ARES_ETIMEOUT; + ++query->timeouts; + next_server(channel, query, now); + } + } + } + channel->last_timeout_processed = now->tv_sec; +} + +/* Handle an answer from a server. */ +static void process_answer(ares_channel channel, unsigned char *abuf, + int alen, int whichserver, int tcp, + struct timeval *now) +{ + int tc, rcode; + unsigned short id; + struct query *query; + struct list_node* list_head; + struct list_node* list_node; + + /* If there's no room in the answer for a header, we can't do much + * with it. */ + if (alen < HFIXEDSZ) + return; + + /* Grab the query ID, truncate bit, and response code from the packet. */ + id = DNS_HEADER_QID(abuf); + tc = DNS_HEADER_TC(abuf); + rcode = DNS_HEADER_RCODE(abuf); + + /* Find the query corresponding to this packet. The queries are + * hashed/bucketed by query id, so this lookup should be quick. + * Note that both the query id and the questions must be the same; + * when the query id wraps around we can have multiple outstanding + * queries with the same query id, so we need to check both the id and + * question. + */ + query = NULL; + list_head = &(channel->queries_by_qid[id % ARES_QID_TABLE_SIZE]); + for (list_node = list_head->next; list_node != list_head; + list_node = list_node->next) + { + struct query *q = list_node->data; + if ((q->qid == id) && same_questions(q->qbuf, q->qlen, abuf, alen)) + { + query = q; + break; + } + } + if (!query) + return; + + /* If we got a truncated UDP packet and are not ignoring truncation, + * don't accept the packet, and switch the query to TCP if we hadn't + * done so already. + */ + if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC)) + { + if (!query->using_tcp) + { + query->using_tcp = 1; + ares__send_query(channel, query, now); + } + return; + } + + /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we + * are ignoring truncation. + */ + if (alen > PACKETSZ && !tcp) + alen = PACKETSZ; + + /* If we aren't passing through all error packets, discard packets + * with SERVFAIL, NOTIMP, or REFUSED response codes. + */ + if (!(channel->flags & ARES_FLAG_NOCHECKRESP)) + { + if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED) + { + skip_server(channel, query, whichserver); + if (query->server == whichserver) + next_server(channel, query, now); + return; + } + } + + end_query(channel, query, ARES_SUCCESS, abuf, alen); +} + +/* Close all the connections that are no longer usable. */ +static void process_broken_connections(ares_channel channel, + struct timeval *now) +{ + int i; + for (i = 0; i < channel->nservers; i++) + { + struct server_state *server = &channel->servers[i]; + if (server->is_broken) + { + handle_error(channel, i, now); + } + } +} + +static void handle_error(ares_channel channel, int whichserver, + struct timeval *now) +{ + struct server_state *server; + struct query *query; + struct list_node list_head; + struct list_node* list_node; + + server = &channel->servers[whichserver]; + + /* Reset communications with this server. */ + ares__close_sockets(channel, server); + + /* Tell all queries talking to this server to move on and not try + * this server again. We steal the current list of queries that were + * in-flight to this server, since when we call next_server this can + * cause the queries to be re-sent to this server, which will + * re-insert these queries in that same server->queries_to_server + * list. + */ + ares__init_list_head(&list_head); + ares__swap_lists(&list_head, &(server->queries_to_server)); + for (list_node = list_head.next; list_node != &list_head; ) + { + query = list_node->data; + list_node = list_node->next; /* in case the query gets deleted */ + assert(query->server == whichserver); + skip_server(channel, query, whichserver); + next_server(channel, query, now); + } + /* Each query should have removed itself from our temporary list as + * it re-sent itself or finished up... + */ + assert(ares__is_list_empty(&list_head)); +} + +static void skip_server(ares_channel channel, struct query *query, + int whichserver) { + /* The given server gave us problems with this query, so if we have + * the luxury of using other servers, then let's skip the + * potentially broken server and just use the others. If we only + * have one server and we need to retry then we should just go ahead + * and re-use that server, since it's our only hope; perhaps we + * just got unlucky, and retrying will work (eg, the server timed + * out our TCP connection just as we were sending another request). + */ + if (channel->nservers > 1) + { + query->server_info[whichserver].skip_server = 1; + } +} + +static void next_server(ares_channel channel, struct query *query, + struct timeval *now) +{ + /* We need to try each server channel->tries times. We have channel->nservers + * servers to try. In total, we need to do channel->nservers * channel->tries + * attempts. Use query->try to remember how many times we already attempted + * this query. Use modular arithmetic to find the next server to try. */ + while (++(query->try) < (channel->nservers * channel->tries)) + { + struct server_state *server; + + /* Move on to the next server. */ + query->server = (query->server + 1) % channel->nservers; + server = &channel->servers[query->server]; + + /* We don't want to use this server if (1) we decided this + * connection is broken, and thus about to be closed, (2) + * we've decided to skip this server because of earlier + * errors we encountered, or (3) we already sent this query + * over this exact connection. + */ + if (!server->is_broken && + !query->server_info[query->server].skip_server && + !(query->using_tcp && + (query->server_info[query->server].tcp_connection_generation == + server->tcp_connection_generation))) + { + ares__send_query(channel, query, now); + return; + } + + /* You might think that with TCP we only need one try. However, + * even when using TCP, servers can time-out our connection just + * as we're sending a request, or close our connection because + * they die, or never send us a reply because they get wedged or + * tickle a bug that drops our request. + */ + } + + /* If we are here, all attempts to perform query failed. */ + end_query(channel, query, query->error_status, NULL, 0); +} + +void ares__send_query(ares_channel channel, struct query *query, + struct timeval *now) +{ + struct send_request *sendreq; + struct server_state *server; + int timeplus; + + server = &channel->servers[query->server]; + if (query->using_tcp) + { + /* Make sure the TCP socket for this server is set up and queue + * a send request. + */ + if (server->tcp_socket == ARES_SOCKET_BAD) + { + if (open_tcp_socket(channel, server) == -1) + { + skip_server(channel, query, query->server); + next_server(channel, query, now); + return; + } + } + sendreq = calloc(1, sizeof(struct send_request)); + if (!sendreq) + { + end_query(channel, query, ARES_ENOMEM, NULL, 0); + return; + } + /* To make the common case fast, we avoid copies by using the + * query's tcpbuf for as long as the query is alive. In the rare + * case where the query ends while it's queued for transmission, + * then we give the sendreq its own copy of the request packet + * and put it in sendreq->data_storage. + */ + sendreq->data_storage = NULL; + sendreq->data = query->tcpbuf; + sendreq->len = query->tcplen; + sendreq->owner_query = query; + sendreq->next = NULL; + if (server->qtail) + server->qtail->next = sendreq; + else + { + SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 1); + server->qhead = sendreq; + } + server->qtail = sendreq; + query->server_info[query->server].tcp_connection_generation = + server->tcp_connection_generation; + } + else + { + if (server->udp_socket == ARES_SOCKET_BAD) + { + if (open_udp_socket(channel, server) == -1) + { + skip_server(channel, query, query->server); + next_server(channel, query, now); + return; + } + } + if (swrite(server->udp_socket, query->qbuf, query->qlen) == -1) + { + /* FIXME: Handle EAGAIN here since it likely can happen. */ + skip_server(channel, query, query->server); + next_server(channel, query, now); + return; + } + } + timeplus = channel->timeout << (query->try / channel->nservers); + timeplus = (timeplus * (9 + (rand () & 7))) / 16; + query->timeout = *now; + ares__timeadd(&query->timeout, + timeplus); + /* Keep track of queries bucketed by timeout, so we can process + * timeout events quickly. + */ + ares__remove_from_list(&(query->queries_by_timeout)); + ares__insert_in_list( + &(query->queries_by_timeout), + &(channel->queries_by_timeout[query->timeout.tv_sec % + ARES_TIMEOUT_TABLE_SIZE])); + + /* Keep track of queries bucketed by server, so we can process server + * errors quickly. + */ + ares__remove_from_list(&(query->queries_to_server)); + ares__insert_in_list(&(query->queries_to_server), + &(server->queries_to_server)); +} + +/* + * setsocknonblock sets the given socket to either blocking or non-blocking + * mode based on the 'nonblock' boolean argument. This function is highly + * portable. + */ +static int setsocknonblock(ares_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */) +{ +#if defined(USE_BLOCKING_SOCKETS) + + return 0; /* returns success */ + +#elif defined(HAVE_FCNTL_O_NONBLOCK) + + /* most recent unix versions */ + int flags; + flags = fcntl(sockfd, F_GETFL, 0); + if (FALSE != nonblock) + return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + else + return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); + +#elif defined(HAVE_IOCTL_FIONBIO) + + /* older unix versions */ + int flags; + flags = nonblock; + return ioctl(sockfd, FIONBIO, &flags); + +#elif defined(HAVE_IOCTLSOCKET_FIONBIO) + +#ifdef WATT32 + char flags; +#else + /* Windows */ + unsigned long flags; +#endif + flags = nonblock; + return ioctlsocket(sockfd, FIONBIO, &flags); + +#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) + + /* Amiga */ + return IoctlSocket(sockfd, FIONBIO, (long)nonblock); + +#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) + + /* BeOS */ + long b = nonblock ? 1 : 0; + return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); + +#else +# error "no non-blocking method was found/used/set" +#endif +} + +static int configure_socket(ares_socket_t s, ares_channel channel) +{ + setsocknonblock(s, TRUE); + +#if defined(FD_CLOEXEC) && !defined(MSDOS) + /* Configure the socket fd as close-on-exec. */ + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) + return -1; +#endif + + /* Set the socket's send and receive buffer sizes. */ + if ((channel->socket_send_buffer_size > 0) && + setsockopt(s, SOL_SOCKET, SO_SNDBUF, + (void *)&channel->socket_send_buffer_size, + sizeof(channel->socket_send_buffer_size)) == -1) + return -1; + + if ((channel->socket_receive_buffer_size > 0) && + setsockopt(s, SOL_SOCKET, SO_RCVBUF, + (void *)&channel->socket_receive_buffer_size, + sizeof(channel->socket_receive_buffer_size)) == -1) + return -1; + + return 0; + } + +static int open_tcp_socket(ares_channel channel, struct server_state *server) +{ + ares_socket_t s; + int opt; + ares_socklen_t salen; + union { + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + } saddr; + struct sockaddr *sa; + + switch (server->addr.family) + { + case AF_INET: + sa = (void *)&saddr.sa4; + salen = sizeof(saddr.sa4); + memset(sa, 0, salen); + saddr.sa4.sin_family = AF_INET; + saddr.sa4.sin_port = (unsigned short)(channel->tcp_port & 0xffff); + memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4, + sizeof(server->addr.addrV4)); + break; + case AF_INET6: + sa = (void *)&saddr.sa6; + salen = sizeof(saddr.sa6); + memset(sa, 0, salen); + saddr.sa6.sin6_family = AF_INET6; + saddr.sa6.sin6_port = (unsigned short)(channel->tcp_port & 0xffff); + memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6, + sizeof(server->addr.addrV6)); + break; + default: + return -1; + } + + /* Acquire a socket. */ + s = socket(server->addr.family, SOCK_STREAM, 0); + if (s == ARES_SOCKET_BAD) + return -1; + + /* Configure it. */ + if (configure_socket(s, channel) < 0) + { + sclose(s); + return -1; + } + +#ifdef TCP_NODELAY + /* + * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not + * in configure_socket). In general, in DNS lookups we're pretty much + * interested in firing off a single request and then waiting for a reply, + * so batching isn't very interesting in general. + */ + opt = 1; + if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, + (void *)&opt, sizeof(opt)) == -1) + { + sclose(s); + return -1; + } +#endif + + /* Connect to the server. */ + if (connect(s, sa, salen) == -1) + { + int err = SOCKERRNO; + + if (err != EINPROGRESS && err != EWOULDBLOCK) + { + sclose(s); + return -1; + } + } + + if (channel->sock_create_cb) + { + int err = channel->sock_create_cb(s, SOCK_STREAM, + channel->sock_create_cb_data); + if (err < 0) + { + sclose(s); + return err; + } + } + + SOCK_STATE_CALLBACK(channel, s, 1, 0); + server->tcp_buffer_pos = 0; + server->tcp_socket = s; + server->tcp_connection_generation = ++channel->tcp_connection_generation; + return 0; +} + +static int open_udp_socket(ares_channel channel, struct server_state *server) +{ + ares_socket_t s; + ares_socklen_t salen; + union { + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + } saddr; + struct sockaddr *sa; + + switch (server->addr.family) + { + case AF_INET: + sa = (void *)&saddr.sa4; + salen = sizeof(saddr.sa4); + memset(sa, 0, salen); + saddr.sa4.sin_family = AF_INET; + saddr.sa4.sin_port = (unsigned short)(channel->udp_port & 0xffff); + memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4, + sizeof(server->addr.addrV4)); + break; + case AF_INET6: + sa = (void *)&saddr.sa6; + salen = sizeof(saddr.sa6); + memset(sa, 0, salen); + saddr.sa6.sin6_family = AF_INET6; + saddr.sa6.sin6_port = (unsigned short)(channel->udp_port & 0xffff); + memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6, + sizeof(server->addr.addrV6)); + break; + default: + return -1; + } + + /* Acquire a socket. */ + s = socket(server->addr.family, SOCK_DGRAM, 0); + if (s == ARES_SOCKET_BAD) + return -1; + + /* Set the socket non-blocking. */ + if (configure_socket(s, channel) < 0) + { + sclose(s); + return -1; + } + + /* Connect to the server. */ + if (connect(s, sa, salen) == -1) + { + int err = SOCKERRNO; + + if (err != EINPROGRESS && err != EWOULDBLOCK) + { + sclose(s); + return -1; + } + } + + if (channel->sock_create_cb) + { + int err = channel->sock_create_cb(s, SOCK_DGRAM, + channel->sock_create_cb_data); + if (err < 0) + { + sclose(s); + return err; + } + } + + SOCK_STATE_CALLBACK(channel, s, 1, 0); + + server->udp_socket = s; + return 0; +} + +static int same_questions(const unsigned char *qbuf, int qlen, + const unsigned char *abuf, int alen) +{ + struct { + const unsigned char *p; + int qdcount; + char *name; + long namelen; + int type; + int dnsclass; + } q, a; + int i, j; + + if (qlen < HFIXEDSZ || alen < HFIXEDSZ) + return 0; + + /* Extract qdcount from the request and reply buffers and compare them. */ + q.qdcount = DNS_HEADER_QDCOUNT(qbuf); + a.qdcount = DNS_HEADER_QDCOUNT(abuf); + if (q.qdcount != a.qdcount) + return 0; + + /* For each question in qbuf, find it in abuf. */ + q.p = qbuf + HFIXEDSZ; + for (i = 0; i < q.qdcount; i++) + { + /* Decode the question in the query. */ + if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen) + != ARES_SUCCESS) + return 0; + q.p += q.namelen; + if (q.p + QFIXEDSZ > qbuf + qlen) + { + free(q.name); + return 0; + } + q.type = DNS_QUESTION_TYPE(q.p); + q.dnsclass = DNS_QUESTION_CLASS(q.p); + q.p += QFIXEDSZ; + + /* Search for this question in the answer. */ + a.p = abuf + HFIXEDSZ; + for (j = 0; j < a.qdcount; j++) + { + /* Decode the question in the answer. */ + if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen) + != ARES_SUCCESS) + { + free(q.name); + return 0; + } + a.p += a.namelen; + if (a.p + QFIXEDSZ > abuf + alen) + { + free(q.name); + free(a.name); + return 0; + } + a.type = DNS_QUESTION_TYPE(a.p); + a.dnsclass = DNS_QUESTION_CLASS(a.p); + a.p += QFIXEDSZ; + + /* Compare the decoded questions. */ + if (strcasecmp(q.name, a.name) == 0 && q.type == a.type + && q.dnsclass == a.dnsclass) + { + free(a.name); + break; + } + free(a.name); + } + + free(q.name); + if (j == a.qdcount) + return 0; + } + return 1; +} + +static int same_address(struct sockaddr *sa, struct ares_addr *aa) +{ + void *addr1; + void *addr2; + + if (sa->sa_family == aa->family) + { + switch (aa->family) + { + case AF_INET: + addr1 = &aa->addrV4; + addr2 = &((struct sockaddr_in *)sa)->sin_addr; + if (memcmp(addr1, addr2, sizeof(aa->addrV4)) == 0) + return 1; /* match */ + break; + case AF_INET6: + addr1 = &aa->addrV6; + addr2 = &((struct sockaddr_in6 *)sa)->sin6_addr; + if (memcmp(addr1, addr2, sizeof(aa->addrV6)) == 0) + return 1; /* match */ + break; + default: + break; + } + } + return 0; /* different */ +} + +static void end_query (ares_channel channel, struct query *query, int status, + unsigned char *abuf, int alen) +{ + int i; + + /* First we check to see if this query ended while one of our send + * queues still has pointers to it. + */ + for (i = 0; i < channel->nservers; i++) + { + struct server_state *server = &channel->servers[i]; + struct send_request *sendreq; + for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) + if (sendreq->owner_query == query) + { + sendreq->owner_query = NULL; + assert(sendreq->data_storage == NULL); + if (status == ARES_SUCCESS) + { + /* We got a reply for this query, but this queued + * sendreq points into this soon-to-be-gone query's + * tcpbuf. Probably this means we timed out and queued + * the query for retransmission, then received a + * response before actually retransmitting. This is + * perfectly fine, so we want to keep the connection + * running smoothly if we can. But in the worst case + * we may have sent only some prefix of the query, + * with some suffix of the query left to send. Also, + * the buffer may be queued on multiple queues. To + * prevent dangling pointers to the query's tcpbuf and + * handle these cases, we just give such sendreqs + * their own copy of the query packet. + */ + sendreq->data_storage = malloc(sendreq->len); + if (sendreq->data_storage != NULL) + { + memcpy(sendreq->data_storage, sendreq->data, sendreq->len); + sendreq->data = sendreq->data_storage; + } + } + if ((status != ARES_SUCCESS) || (sendreq->data_storage == NULL)) + { + /* We encountered an error (probably a timeout, + * suggesting the DNS server we're talking to is + * probably unreachable, wedged, or severely + * overloaded) or we couldn't copy the request, so + * mark the connection as broken. When we get to + * process_broken_connections() we'll close the + * connection and try to re-send requests to another + * server. + */ + server->is_broken = 1; + /* Just to be paranoid, zero out this sendreq... */ + sendreq->data = NULL; + sendreq->len = 0; + } + } + } + + /* Invoke the callback */ + query->callback(query->arg, status, query->timeouts, abuf, alen); + ares__free_query(query); + + /* Simple cleanup policy: if no queries are remaining, close all + * network sockets unless STAYOPEN is set. + */ + if (!(channel->flags & ARES_FLAG_STAYOPEN) && + ares__is_list_empty(&(channel->all_queries))) + { + for (i = 0; i < channel->nservers; i++) + ares__close_sockets(channel, &channel->servers[i]); + } +} + +void ares__free_query(struct query *query) +{ + /* Remove the query from all the lists in which it is linked */ + ares__remove_from_list(&(query->queries_by_qid)); + ares__remove_from_list(&(query->queries_by_timeout)); + ares__remove_from_list(&(query->queries_to_server)); + ares__remove_from_list(&(query->all_queries)); + /* Zero out some important stuff, to help catch bugs */ + query->callback = NULL; + query->arg = NULL; + /* Deallocate the memory associated with the query */ + free(query->tcpbuf); + free(query->server_info); + free(query); +} diff --git a/deps/c-ares/ares_query.c b/deps/c-ares/ares_query.c new file mode 100644 index 00000000000..2a717fb3c60 --- /dev/null +++ b/deps/c-ares/ares_query.c @@ -0,0 +1,184 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +struct qquery { + ares_callback callback; + void *arg; +}; + +static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen); + +void ares__rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len) +{ + unsigned char x; + unsigned char y; + unsigned char* state; + unsigned char xorIndex; + short counter; + + x = key->x; + y = key->y; + + state = &key->state[0]; + for(counter = 0; counter < buffer_len; counter ++) + { + x = (unsigned char)((x + 1) % 256); + y = (unsigned char)((state[x] + y) % 256); + ARES_SWAP_BYTE(&state[x], &state[y]); + + xorIndex = (unsigned char)((state[x] + state[y]) % 256); + + buffer_ptr[counter] = (unsigned char)(buffer_ptr[counter]^state[xorIndex]); + } + key->x = x; + key->y = y; +} + +static struct query* find_query_by_id(ares_channel channel, unsigned short id) +{ + unsigned short qid; + struct list_node* list_head; + struct list_node* list_node; + DNS_HEADER_SET_QID(((unsigned char*)&qid), id); + + /* Find the query corresponding to this packet. */ + list_head = &(channel->queries_by_qid[qid % ARES_QID_TABLE_SIZE]); + for (list_node = list_head->next; list_node != list_head; + list_node = list_node->next) + { + struct query *q = list_node->data; + if (q->qid == qid) + return q; + } + return NULL; +} + + +/* a unique query id is generated using an rc4 key. Since the id may already + be used by a running query (as infrequent as it may be), a lookup is + performed per id generation. In practice this search should happen only + once per newly generated id +*/ +static unsigned short generate_unique_id(ares_channel channel) +{ + unsigned short id; + + do { + id = ares__generate_new_id(&channel->id_key); + } while (find_query_by_id(channel, id)); + + return (unsigned short)id; +} + +void ares_query(ares_channel channel, const char *name, int dnsclass, + int type, ares_callback callback, void *arg) +{ + struct qquery *qquery; + unsigned char *qbuf; + int qlen, rd, status; + + /* Compose the query. */ + rd = !(channel->flags & ARES_FLAG_NORECURSE); + status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf, + &qlen); + if (status != ARES_SUCCESS) + { + if (qbuf != NULL) free(qbuf); + callback(arg, status, 0, NULL, 0); + return; + } + + channel->next_id = generate_unique_id(channel); + + /* Allocate and fill in the query structure. */ + qquery = malloc(sizeof(struct qquery)); + if (!qquery) + { + ares_free_string(qbuf); + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + qquery->callback = callback; + qquery->arg = arg; + + /* Send it off. qcallback will be called when we get an answer. */ + ares_send(channel, qbuf, qlen, qcallback, qquery); + ares_free_string(qbuf); +} + +static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) +{ + struct qquery *qquery = (struct qquery *) arg; + unsigned int ancount; + int rcode; + + if (status != ARES_SUCCESS) + qquery->callback(qquery->arg, status, timeouts, abuf, alen); + else + { + /* Pull the response code and answer count from the packet. */ + rcode = DNS_HEADER_RCODE(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + + /* Convert errors. */ + switch (rcode) + { + case NOERROR: + status = (ancount > 0) ? ARES_SUCCESS : ARES_ENODATA; + break; + case FORMERR: + status = ARES_EFORMERR; + break; + case SERVFAIL: + status = ARES_ESERVFAIL; + break; + case NXDOMAIN: + status = ARES_ENOTFOUND; + break; + case NOTIMP: + status = ARES_ENOTIMP; + break; + case REFUSED: + status = ARES_EREFUSED; + break; + } + qquery->callback(qquery->arg, status, timeouts, abuf, alen); + } + free(qquery); +} diff --git a/deps/c-ares/ares_rules.h b/deps/c-ares/ares_rules.h new file mode 100644 index 00000000000..cdacf4a1439 --- /dev/null +++ b/deps/c-ares/ares_rules.h @@ -0,0 +1,145 @@ +#ifndef __CARES_RULES_H +#define __CARES_RULES_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by ares.h when an application is + * being built using an already built c-ares library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the ares_build.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the c-ares development mailing list: + * http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built c-ares library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CARES_SIZEOF_LONG_is_missing +#endif + +#ifndef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_is_missing +#endif + +#ifndef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CareschkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CareschkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __cares_rule_01__ + [CareschkszEQ(long, CARES_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * ares_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __cares_rule_02__ + [CareschkszEQ(ares_socklen_t, CARES_SIZEOF_ARES_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of ares_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __cares_rule_03__ + [CareschkszGE(ares_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * Get rid of macros private to this header file. + */ + +#undef CareschkszEQ +#undef CareschkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CARES_PULL_WS2TCPIP_H +#undef CARES_PULL_SYS_TYPES_H +#undef CARES_PULL_SYS_SOCKET_H + +#undef CARES_TYPEOF_ARES_SOCKLEN_T + +#endif /* __CARES_RULES_H */ diff --git a/deps/c-ares/ares_search.c b/deps/c-ares/ares_search.c new file mode 100644 index 00000000000..8673c289f96 --- /dev/null +++ b/deps/c-ares/ares_search.c @@ -0,0 +1,323 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "ares.h" +#include "ares_private.h" + +struct search_query { + /* Arguments passed to ares_search */ + ares_channel channel; + char *name; /* copied into an allocated buffer */ + int dnsclass; + int type; + ares_callback callback; + void *arg; + + int status_as_is; /* error status from trying as-is */ + int next_domain; /* next search domain to try */ + int trying_as_is; /* current query is for name as-is */ + int timeouts; /* number of timeouts we saw for this request */ + int ever_got_nodata; /* did we ever get ARES_ENODATA along the way? */ +}; + +static void search_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen); +static void end_squery(struct search_query *squery, int status, + unsigned char *abuf, int alen); +static int cat_domain(const char *name, const char *domain, char **s); +static int single_domain(ares_channel channel, const char *name, char **s); + +void ares_search(ares_channel channel, const char *name, int dnsclass, + int type, ares_callback callback, void *arg) +{ + struct search_query *squery; + char *s; + const char *p; + int status, ndots; + + /* If name only yields one domain to search, then we don't have + * to keep extra state, so just do an ares_query(). + */ + status = single_domain(channel, name, &s); + if (status != ARES_SUCCESS) + { + callback(arg, status, 0, NULL, 0); + return; + } + if (s) + { + ares_query(channel, s, dnsclass, type, callback, arg); + free(s); + return; + } + + /* Allocate a search_query structure to hold the state necessary for + * doing multiple lookups. + */ + squery = malloc(sizeof(struct search_query)); + if (!squery) + { + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + squery->channel = channel; + squery->name = strdup(name); + if (!squery->name) + { + free(squery); + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + squery->dnsclass = dnsclass; + squery->type = type; + squery->status_as_is = -1; + squery->callback = callback; + squery->arg = arg; + squery->timeouts = 0; + squery->ever_got_nodata = 0; + + /* Count the number of dots in name. */ + ndots = 0; + for (p = name; *p; p++) + { + if (*p == '.') + ndots++; + } + + /* If ndots is at least the channel ndots threshold (usually 1), + * then we try the name as-is first. Otherwise, we try the name + * as-is last. + */ + if (ndots >= channel->ndots) + { + /* Try the name as-is first. */ + squery->next_domain = 0; + squery->trying_as_is = 1; + ares_query(channel, name, dnsclass, type, search_callback, squery); + } + else + { + /* Try the name as-is last; start with the first search domain. */ + squery->next_domain = 1; + squery->trying_as_is = 0; + status = cat_domain(name, channel->domains[0], &s); + if (status == ARES_SUCCESS) + { + ares_query(channel, s, dnsclass, type, search_callback, squery); + free(s); + } + else + { + /* failed, free the malloc()ed memory */ + free(squery->name); + free(squery); + callback(arg, status, 0, NULL, 0); + } + } +} + +static void search_callback(void *arg, int status, int timeouts, + unsigned char *abuf, int alen) +{ + struct search_query *squery = (struct search_query *) arg; + ares_channel channel = squery->channel; + char *s; + + squery->timeouts += timeouts; + + /* Stop searching unless we got a non-fatal error. */ + if (status != ARES_ENODATA && status != ARES_ESERVFAIL + && status != ARES_ENOTFOUND) + end_squery(squery, status, abuf, alen); + else + { + /* Save the status if we were trying as-is. */ + if (squery->trying_as_is) + squery->status_as_is = status; + + /* + * If we ever get ARES_ENODATA along the way, record that; if the search + * should run to the very end and we got at least one ARES_ENODATA, + * then callers like ares_gethostbyname() may want to try a T_A search + * even if the last domain we queried for T_AAAA resource records + * returned ARES_ENOTFOUND. + */ + if (status == ARES_ENODATA) + squery->ever_got_nodata = 1; + + if (squery->next_domain < channel->ndomains) + { + /* Try the next domain. */ + status = cat_domain(squery->name, + channel->domains[squery->next_domain], &s); + if (status != ARES_SUCCESS) + end_squery(squery, status, NULL, 0); + else + { + squery->trying_as_is = 0; + squery->next_domain++; + ares_query(channel, s, squery->dnsclass, squery->type, + search_callback, squery); + free(s); + } + } + else if (squery->status_as_is == -1) + { + /* Try the name as-is at the end. */ + squery->trying_as_is = 1; + ares_query(channel, squery->name, squery->dnsclass, squery->type, + search_callback, squery); + } + else { + if (squery->status_as_is == ARES_ENOTFOUND && squery->ever_got_nodata) { + end_squery(squery, ARES_ENODATA, NULL, 0); + } + else + end_squery(squery, squery->status_as_is, NULL, 0); + } + } +} + +static void end_squery(struct search_query *squery, int status, + unsigned char *abuf, int alen) +{ + squery->callback(squery->arg, status, squery->timeouts, abuf, alen); + free(squery->name); + free(squery); +} + +/* Concatenate two domains. */ +static int cat_domain(const char *name, const char *domain, char **s) +{ + size_t nlen = strlen(name); + size_t dlen = strlen(domain); + + *s = malloc(nlen + 1 + dlen + 1); + if (!*s) + return ARES_ENOMEM; + memcpy(*s, name, nlen); + (*s)[nlen] = '.'; + memcpy(*s + nlen + 1, domain, dlen); + (*s)[nlen + 1 + dlen] = 0; + return ARES_SUCCESS; +} + +/* Determine if this name only yields one query. If it does, set *s to + * the string we should query, in an allocated buffer. If not, set *s + * to NULL. + */ +static int single_domain(ares_channel channel, const char *name, char **s) +{ + size_t len = strlen(name); + const char *hostaliases; + FILE *fp; + char *line = NULL; + int status; + size_t linesize; + const char *p, *q; + int error; + + /* If the name contains a trailing dot, then the single query is the name + * sans the trailing dot. + */ + if (name[len - 1] == '.') + { + *s = strdup(name); + return (*s) ? ARES_SUCCESS : ARES_ENOMEM; + } + + if (!(channel->flags & ARES_FLAG_NOALIASES) && !strchr(name, '.')) + { + /* The name might be a host alias. */ + hostaliases = getenv("HOSTALIASES"); + if (hostaliases) + { + fp = fopen(hostaliases, "r"); + if (fp) + { + while ((status = ares__read_line(fp, &line, &linesize)) + == ARES_SUCCESS) + { + if (strncasecmp(line, name, len) != 0 || + !ISSPACE(line[len])) + continue; + p = line + len; + while (ISSPACE(*p)) + p++; + if (*p) + { + q = p + 1; + while (*q && !ISSPACE(*q)) + q++; + *s = malloc(q - p + 1); + if (*s) + { + memcpy(*s, p, q - p); + (*s)[q - p] = 0; + } + free(line); + fclose(fp); + return (*s) ? ARES_SUCCESS : ARES_ENOMEM; + } + } + free(line); + fclose(fp); + if (status != ARES_SUCCESS) + return status; + } + else + { + error = errno; + switch(error) + { + case ENOENT: + case ESRCH: + break; + default: + DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", + error, strerror(error))); + DEBUGF(fprintf(stderr, "Error opening file: %s\n", + hostaliases)); + *s = NULL; + return ARES_EFILE; + } + } + } + } + + if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0) + { + /* No domain search to do; just try the name as-is. */ + *s = strdup(name); + return (*s) ? ARES_SUCCESS : ARES_ENOMEM; + } + + *s = NULL; + return ARES_SUCCESS; +} diff --git a/deps/c-ares/ares_send.c b/deps/c-ares/ares_send.c new file mode 100644 index 00000000000..c2b006537fd --- /dev/null +++ b/deps/c-ares/ares_send.c @@ -0,0 +1,135 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_private.h" + +void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, + ares_callback callback, void *arg) +{ + struct query *query; + int i; + struct timeval now; + + /* Verify that the query is at least long enough to hold the header. */ + if (qlen < HFIXEDSZ || qlen >= (1 << 16)) + { + callback(arg, ARES_EBADQUERY, 0, NULL, 0); + return; + } + + /* Allocate space for query and allocated fields. */ + query = malloc(sizeof(struct query)); + if (!query) + { + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + query->tcpbuf = malloc(qlen + 2); + if (!query->tcpbuf) + { + free(query); + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + query->server_info = malloc(channel->nservers * + sizeof(query->server_info[0])); + if (!query->server_info) + { + free(query->tcpbuf); + free(query); + callback(arg, ARES_ENOMEM, 0, NULL, 0); + return; + } + + /* Compute the query ID. Start with no timeout. */ + query->qid = (unsigned short)DNS_HEADER_QID(qbuf); + query->timeout.tv_sec = 0; + query->timeout.tv_usec = 0; + + /* Form the TCP query buffer by prepending qlen (as two + * network-order bytes) to qbuf. + */ + query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff); + query->tcpbuf[1] = (unsigned char)(qlen & 0xff); + memcpy(query->tcpbuf + 2, qbuf, qlen); + query->tcplen = qlen + 2; + + /* Fill in query arguments. */ + query->qbuf = query->tcpbuf + 2; + query->qlen = qlen; + query->callback = callback; + query->arg = arg; + + /* Initialize query status. */ + query->try = 0; + + /* Choose the server to send the query to. If rotation is enabled, keep track + * of the next server we want to use. */ + query->server = channel->last_server; + if (channel->rotate == 1) + channel->last_server = (channel->last_server + 1) % channel->nservers; + + for (i = 0; i < channel->nservers; i++) + { + query->server_info[i].skip_server = 0; + query->server_info[i].tcp_connection_generation = 0; + } + query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ; + query->error_status = ARES_ECONNREFUSED; + query->timeouts = 0; + + /* Initialize our list nodes. */ + ares__init_list_node(&(query->queries_by_qid), query); + ares__init_list_node(&(query->queries_by_timeout), query); + ares__init_list_node(&(query->queries_to_server), query); + ares__init_list_node(&(query->all_queries), query); + + /* Chain the query into the list of all queries. */ + ares__insert_in_list(&(query->all_queries), &(channel->all_queries)); + /* Keep track of queries bucketed by qid, so we can process DNS + * responses quickly. + */ + ares__insert_in_list( + &(query->queries_by_qid), + &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE])); + + /* Perform the first query action. */ + now = ares__tvnow(); + ares__send_query(channel, query, &now); +} diff --git a/deps/c-ares/ares_strcasecmp.c b/deps/c-ares/ares_strcasecmp.c new file mode 100644 index 00000000000..30d64b91162 --- /dev/null +++ b/deps/c-ares/ares_strcasecmp.c @@ -0,0 +1,67 @@ + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares_strcasecmp.h" + +#ifndef HAVE_STRCASECMP +int ares_strcasecmp(const char *a, const char *b) +{ +#if defined(HAVE_STRCMPI) + return strcmpi(a, b); +#elif defined(HAVE_STRICMP) + return stricmp(a, b); +#else + size_t i; + + for (i = 0; i < (size_t)-1; i++) { + int c1 = ISUPPER(a[i]) ? tolower(a[i]) : a[i]; + int c2 = ISUPPER(b[i]) ? tolower(b[i]) : b[i]; + if (c1 != c2) + return c1-c2; + if (!c1) + break; + } + return 0; +#endif +} +#endif + +#ifndef HAVE_STRNCASECMP +int ares_strncasecmp(const char *a, const char *b, size_t n) +{ +#if defined(HAVE_STRNCMPI) + return strncmpi(a, b, n); +#elif defined(HAVE_STRNICMP) + return strnicmp(a, b, n); +#else + size_t i; + + for (i = 0; i < n; i++) { + int c1 = ISUPPER(a[i]) ? tolower(a[i]) : a[i]; + int c2 = ISUPPER(b[i]) ? tolower(b[i]) : b[i]; + if (c1 != c2) + return c1-c2; + if (!c1) + break; + } + return 0; +#endif +} +#endif + diff --git a/deps/c-ares/ares_strcasecmp.h b/deps/c-ares/ares_strcasecmp.h new file mode 100644 index 00000000000..28164d74b8c --- /dev/null +++ b/deps/c-ares/ares_strcasecmp.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CARES_STRCASECMP_H +#define HEADER_CARES_STRCASECMP_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifndef HAVE_STRCASECMP +extern int ares_strcasecmp(const char *a, const char *b); +#endif + +#ifndef HAVE_STRNCASECMP +extern int ares_strncasecmp(const char *a, const char *b, size_t n); +#endif + +#endif /* HEADER_CARES_STRCASECMP_H */ diff --git a/deps/c-ares/ares_strdup.c b/deps/c-ares/ares_strdup.c new file mode 100644 index 00000000000..6742c6f6b5f --- /dev/null +++ b/deps/c-ares/ares_strdup.c @@ -0,0 +1,43 @@ + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares_strdup.h" + +#ifndef HAVE_STRDUP +char *ares_strdup(const char *s1) +{ + size_t sz; + char * s2; + + if(s1) { + sz = strlen(s1); + if(sz < (size_t)-1) { + sz++; + if(sz < ((size_t)-1) / sizeof(char)) { + s2 = malloc(sz * sizeof(char)); + if(s2) { + memcpy(s2, s1, sz * sizeof(char)); + return s2; + } + } + } + } + return (char *)NULL; +} +#endif diff --git a/deps/c-ares/ares_strdup.h b/deps/c-ares/ares_strdup.h new file mode 100644 index 00000000000..980da526397 --- /dev/null +++ b/deps/c-ares/ares_strdup.h @@ -0,0 +1,27 @@ +#ifndef HEADER_CARES_STRDUP_H +#define HEADER_CARES_STRDUP_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifndef HAVE_STRDUP +extern char *ares_strdup(const char *s1); +#endif + +#endif /* HEADER_CARES_STRDUP_H */ diff --git a/deps/c-ares/ares_strerror.c b/deps/c-ares/ares_strerror.c new file mode 100644 index 00000000000..70af5b68daa --- /dev/null +++ b/deps/c-ares/ares_strerror.c @@ -0,0 +1,57 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include +#include "ares.h" + +const char *ares_strerror(int code) +{ + /* Return a string literal from a table. */ + const char *errtext[] = { + "Successful completion", + "DNS server returned answer with no data", + "DNS server claims query was misformatted", + "DNS server returned general failure", + "Domain name not found", + "DNS server does not implement requested operation", + "DNS server refused query", + "Misformatted DNS query", + "Misformatted domain name", + "Unsupported address family", + "Misformatted DNS reply", + "Could not contact DNS servers", + "Timeout while contacting DNS servers", + "End of file", + "Error reading file", + "Out of memory", + "Channel is being destroyed", + "Misformatted string", + "Illegal flags specified", + "Given hostname is not numeric", + "Illegal hints flags specified", + "c-ares library initialization not yet performed", + "Error loading iphlpapi.dll", + "Could not find GetNetworkParams function", + "DNS query cancelled" + }; + + if(code >= 0 && code < (int)(sizeof(errtext) / sizeof(*errtext))) + return errtext[code]; + else + return "unknown"; +} diff --git a/deps/c-ares/ares_timeout.c b/deps/c-ares/ares_timeout.c new file mode 100644 index 00000000000..72ea0dc3fc3 --- /dev/null +++ b/deps/c-ares/ares_timeout.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include + +#include "ares.h" +#include "ares_private.h" + +/* WARNING: Beware that this is linear in the number of outstanding + * requests! You are probably far better off just calling ares_process() + * once per second, rather than calling ares_timeout() to figure out + * when to next call ares_process(). + */ +struct timeval *ares_timeout(ares_channel channel, struct timeval *maxtv, + struct timeval *tvbuf) +{ + struct query *query; + struct list_node* list_head; + struct list_node* list_node; + struct timeval now; + struct timeval nextstop; + long offset, min_offset; + + /* No queries, no timeout (and no fetch of the current time). */ + if (ares__is_list_empty(&(channel->all_queries))) + return maxtv; + + /* Find the minimum timeout for the current set of queries. */ + now = ares__tvnow(); + min_offset = -1; + + list_head = &(channel->all_queries); + for (list_node = list_head->next; list_node != list_head; + list_node = list_node->next) + { + query = list_node->data; + if (query->timeout.tv_sec == 0) + continue; + offset = ares__timeoffset(&now, &query->timeout); + if (offset < 0) + offset = 0; + if (min_offset == -1 || offset < min_offset) + min_offset = offset; + } + + if(min_offset != -1) { + nextstop.tv_sec = min_offset/1000; + nextstop.tv_usec = (min_offset%1000)*1000; + } + + /* If we found a minimum timeout and it's sooner than the one specified in + * maxtv (if any), return it. Otherwise go with maxtv. + */ + if (min_offset != -1 && (!maxtv || ares__timedout(maxtv, &nextstop))) + { + *tvbuf = nextstop; + return tvbuf; + } + else + return maxtv; +} diff --git a/deps/c-ares/ares_version.c b/deps/c-ares/ares_version.c new file mode 100644 index 00000000000..0f7d0371055 --- /dev/null +++ b/deps/c-ares/ares_version.c @@ -0,0 +1,12 @@ +/* $Id$ */ + +#include "ares_setup.h" +#include "ares.h" + +const char *ares_version(int *version) +{ + if(version) + *version = ARES_VERSION; + + return ARES_VERSION_STR; +} diff --git a/deps/c-ares/ares_version.h b/deps/c-ares/ares_version.h new file mode 100644 index 00000000000..59dbeb21645 --- /dev/null +++ b/deps/c-ares/ares_version.h @@ -0,0 +1,22 @@ +/* $Id$ */ + +#ifndef ARES__VERSION_H +#define ARES__VERSION_H + +#define ARES_VERSION_MAJOR 1 +#define ARES_VERSION_MINOR 7 +#define ARES_VERSION_PATCH 1 +#define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\ + (ARES_VERSION_MINOR<<8)|\ + (ARES_VERSION_PATCH)) +#define ARES_VERSION_STR "1.7.1" + +#if (ARES_VERSION >= 0x010700) +# define CARES_HAVE_ARES_LIBRARY_INIT 1 +# define CARES_HAVE_ARES_LIBRARY_CLEANUP 1 +#else +# undef CARES_HAVE_ARES_LIBRARY_INIT +# undef CARES_HAVE_ARES_LIBRARY_CLEANUP +#endif + +#endif diff --git a/deps/c-ares/ares_writev.c b/deps/c-ares/ares_writev.c new file mode 100644 index 00000000000..4c12942d791 --- /dev/null +++ b/deps/c-ares/ares_writev.c @@ -0,0 +1,80 @@ + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +#ifdef HAVE_LIMITS_H +# include +#endif + +#include "ares.h" +#include "ares_private.h" + +#ifndef HAVE_WRITEV +ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt) +{ + char *buffer, *bp; + int i; + size_t bytes = 0; + ssize_t result; + + /* Validate iovcnt */ + if (iovcnt <= 0) + { + SET_ERRNO(EINVAL); + return (-1); + } + + /* Validate and find the sum of the iov_len values in the iov array */ + for (i = 0; i < iovcnt; i++) + { + if (iov[i].iov_len > INT_MAX - bytes) + { + SET_ERRNO(EINVAL); + return (-1); + } + bytes += iov[i].iov_len; + } + + if (bytes == 0) + return (0); + + /* Allocate a temporary buffer to hold the data */ + buffer = malloc(bytes); + if (!buffer) + { + SET_ERRNO(ENOMEM); + return (-1); + } + + /* Copy the data into buffer */ + for (bp = buffer, i = 0; i < iovcnt; ++i) + { + memcpy (bp, iov[i].iov_base, iov[i].iov_len); + bp += iov[i].iov_len; + } + + /* Send buffer contents */ + result = swrite(s, buffer, bytes); + + free(buffer); + + return (result); +} +#endif + diff --git a/deps/c-ares/ares_writev.h b/deps/c-ares/ares_writev.h new file mode 100644 index 00000000000..860b2943ff2 --- /dev/null +++ b/deps/c-ares/ares_writev.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CARES_WRITEV_H +#define HEADER_CARES_WRITEV_H + +/* $Id$ */ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares.h" + +#ifndef HAVE_WRITEV + +/* Structure for scatter/gather I/O. */ +struct iovec +{ + void *iov_base; /* Pointer to data. */ + size_t iov_len; /* Length of data. */ +}; + +extern ssize_t ares_writev(ares_socket_t s, const struct iovec *iov, int iovcnt); + +#endif + +#endif /* HEADER_CARES_WRITEV_H */ diff --git a/deps/c-ares/bitncmp.c b/deps/c-ares/bitncmp.c new file mode 100644 index 00000000000..2ec8dc58bbe --- /dev/null +++ b/deps/c-ares/bitncmp.c @@ -0,0 +1,60 @@ +/* $Id$ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HAVE_BITNCMP + +#include "ares_setup.h" +#include "bitncmp.h" + +/* + * int + * bitncmp(l, r, n) + * compare bit masks l and r, for n bits. + * return: + * -1, 1, or 0 in the libc tradition. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +ares_bitncmp(const void *l, const void *r, int n) { + unsigned int lb, rb; + int x, b; + + b = n / 8; + x = memcmp(l, r, b); + if (x || (n % 8) == 0) + return (x); + + lb = ((const unsigned char *)l)[b]; + rb = ((const unsigned char *)r)[b]; + for (b = n % 8; b > 0; b--) { + if ((lb & 0x80) != (rb & 0x80)) { + if (lb & 0x80) + return (1); + return (-1); + } + lb <<= 1; + rb <<= 1; + } + return (0); +} +#endif diff --git a/deps/c-ares/bitncmp.h b/deps/c-ares/bitncmp.h new file mode 100644 index 00000000000..acdd45f0fc2 --- /dev/null +++ b/deps/c-ares/bitncmp.h @@ -0,0 +1,27 @@ +#ifndef __ARES_BITNCMP_H +#define __ARES_BITNCMP_H + +/* $Id$ */ + +/* Copyright (C) 2005 by Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef HAVE_BITNCMP +int ares_bitncmp(const void *l, const void *r, int n); +#else +#define ares_bitncmp(x,y,z) bitncmp(x,y,z) +#endif + +#endif /* __ARES_BITNCMP_H */ diff --git a/deps/c-ares/get_ver.awk b/deps/c-ares/get_ver.awk new file mode 100644 index 00000000000..322f280c07f --- /dev/null +++ b/deps/c-ares/get_ver.awk @@ -0,0 +1,36 @@ +# *************************************************************************** +# * Project: c-ares +# * +# * $Id$ +# *************************************************************************** +# awk script which fetches c-ares version number and string from input +# file and writes them to STDOUT. Here you can get an awk version for Win32: +# http://www.gknw.net/development/prgtools/awk-20070501.zip +# +BEGIN { + if (match (ARGV[1], /ares_version.h/)) { + while ((getline < ARGV[1]) > 0) { + if (match ($0, /^#define ARES_COPYRIGHT "[^"]+"$/)) { + libcares_copyright_str = substr($0, 25, length($0)-25); + } + else if (match ($0, /^#define ARES_VERSION_STR "[^"]+"$/)) { + libcares_ver_str = substr($3, 2, length($3)-2); + } + else if (match ($0, /^#define ARES_VERSION_MAJOR [0-9]+$/)) { + libcares_ver_major = substr($3, 1, length($3)); + } + else if (match ($0, /^#define ARES_VERSION_MINOR [0-9]+$/)) { + libcares_ver_minor = substr($3, 1, length($3)); + } + else if (match ($0, /^#define ARES_VERSION_PATCH [0-9]+$/)) { + libcares_ver_patch = substr($3, 1, length($3)); + } + } + libcares_ver = libcares_ver_major "," libcares_ver_minor "," libcares_ver_patch; + print "LIBCARES_VERSION = " libcares_ver ""; + print "LIBCARES_VERSION_STR = " libcares_ver_str ""; + print "LIBCARES_COPYRIGHT_STR = " libcares_copyright_str ""; + } +} + + diff --git a/deps/c-ares/inet_net_pton.c b/deps/c-ares/inet_net_pton.c new file mode 100644 index 00000000000..9c4717ab1aa --- /dev/null +++ b/deps/c-ares/inet_net_pton.c @@ -0,0 +1,447 @@ +/* $Id$ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "ares.h" +#include "ares_ipv6.h" +#include "inet_net_pton.h" + +#if !defined(HAVE_INET_NET_PTON) || !defined(HAVE_INET_NET_PTON_IPV6) + +/* + * static int + * inet_net_pton_ipv4(src, dst, size) + * convert IPv4 network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not an IPv4 network specification. + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0b11110000 in its fourth octet. + * note: + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid loosing the + * actual last winsock error. So use macro ERRNO to fetch the + * errno this funtion sets when returning (-1), not SOCKERRNO. + * author: + * Paul Vixie (ISC), June 1996 + */ +static int +inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size) +{ + static const char xdigits[] = "0123456789abcdef"; + static const char digits[] = "0123456789"; + int n, ch, tmp = 0, dirty, bits; + const unsigned char *odst = dst; + + ch = *src++; + if (ch == '0' && (src[0] == 'x' || src[0] == 'X') + && ISXDIGIT(src[1])) { + /* Hexadecimal: Eat nybble string. */ + if (!size) + goto emsgsize; + dirty = 0; + src++; /* skip x or X. */ + while ((ch = *src++) != '\0' && ISXDIGIT(ch)) { + if (ISUPPER(ch)) + ch = tolower(ch); + n = (int)(strchr(xdigits, ch) - xdigits); + if (dirty == 0) + tmp = n; + else + tmp = (tmp << 4) | n; + if (++dirty == 2) { + if (!size--) + goto emsgsize; + *dst++ = (unsigned char) tmp; + dirty = 0; + } + } + if (dirty) { /* Odd trailing nybble? */ + if (!size--) + goto emsgsize; + *dst++ = (unsigned char) (tmp << 4); + } + } else if (ISDIGIT(ch)) { + /* Decimal: eat dotted digit string. */ + for (;;) { + tmp = 0; + do { + n = (int)(strchr(digits, ch) - digits); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = *src++) != '\0' && + ISDIGIT(ch)); + if (!size--) + goto emsgsize; + *dst++ = (unsigned char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + ch = *src++; + if (!ISDIGIT(ch)) + goto enoent; + } + } else + goto enoent; + + bits = -1; + if (ch == '/' && + ISDIGIT(src[0]) && dst > odst) { + /* CIDR width specifier. Nothing can follow it. */ + ch = *src++; /* Skip over the /. */ + bits = 0; + do { + n = (int)(strchr(digits, ch) - digits); + bits *= 10; + bits += n; + } while ((ch = *src++) != '\0' && ISDIGIT(ch)); + if (ch != '\0') + goto enoent; + if (bits > 32) + goto emsgsize; + } + + /* Firey death and destruction unless we prefetched EOS. */ + if (ch != '\0') + goto enoent; + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + /* If no CIDR spec was given, infer width from net class. */ + if (bits == -1) { + if (*odst >= 240) /* Class E */ + bits = 32; + else if (*odst >= 224) /* Class D */ + bits = 8; + else if (*odst >= 192) /* Class C */ + bits = 24; + else if (*odst >= 128) /* Class B */ + bits = 16; + else /* Class A */ + bits = 8; + /* If imputed mask is narrower than specified octets, widen. */ + if (bits < ((dst - odst) * 8)) + bits = (int)(dst - odst) * 8; + /* + * If there are no additional bits specified for a class D + * address adjust bits to 4. + */ + if (bits == 8 && *odst == 224) + bits = 4; + } + /* Extend network to cover the actual mask. */ + while (bits > ((dst - odst) * 8)) { + if (!size--) + goto emsgsize; + *dst++ = '\0'; + } + return (bits); + + enoent: + SET_ERRNO(ENOENT); + return (-1); + + emsgsize: + SET_ERRNO(EMSGSIZE); + return (-1); +} + +static int +getbits(const char *src, int *bitsp) +{ + static const char digits[] = "0123456789"; + int n; + int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /* no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 128) /* range */ + return (0); + continue; + } + return (0); + } + if (n == 0) + return (0); + *bitsp = val; + return (1); +} + +static int +getv4(const char *src, unsigned char *dst, int *bitsp) +{ + static const char digits[] = "0123456789"; + unsigned char *odst = dst; + int n; + unsigned int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /* no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 255) /* range */ + return (0); + continue; + } + if (ch == '.' || ch == '/') { + if (dst - odst > 3) /* too many octets? */ + return (0); + *dst++ = (unsigned char)val; + if (ch == '/') + return (getbits(src, bitsp)); + val = 0; + n = 0; + continue; + } + return (0); + } + if (n == 0) + return (0); + if (dst - odst > 3) /* too many octets? */ + return (0); + *dst++ = (unsigned char)val; + return (1); +} + +static int +inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + int digits; + int bits; + size_t bytes; + int words; + int ipv4; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + goto enoent; + curtok = src; + saw_xdigit = 0; + val = 0; + digits = 0; + bits = -1; + ipv4 = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++digits > 4) + goto enoent; + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + goto enoent; + colonp = tp; + continue; + } else if (*src == '\0') + goto enoent; + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char)((val >> 8) & 0xff); + *tp++ = (unsigned char)(val & 0xff); + saw_xdigit = 0; + digits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + getv4(curtok, tp, &bits) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + ipv4 = 1; + break; /* '\0' was seen by inet_pton4(). */ + } + if (ch == '/' && getbits(src, &bits) > 0) + break; + goto enoent; + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + goto enoent; + *tp++ = (unsigned char)((val >> 8) & 0xff); + *tp++ = (unsigned char)(val & 0xff); + } + if (bits == -1) + bits = 128; + + words = (bits + 15) / 16; + if (words < 2) + words = 2; + if (ipv4) + words = 8; + endp = tmp + 2 * words; + + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = (int)(tp - colonp); + int i; + + if (tp == endp) + goto enoent; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + goto enoent; + + bytes = (bits + 7) / 8; + if (bytes > size) + goto emsgsize; + memcpy(dst, tmp, bytes); + return (bits); + + enoent: + SET_ERRNO(ENOENT); + return (-1); + + emsgsize: + SET_ERRNO(EMSGSIZE); + return (-1); +} + +/* + * int + * inet_net_pton(af, src, dst, size) + * convert network number from presentation to network format. + * accepts hex octets, hex strings, decimal octets, and /CIDR. + * "size" is in bytes and describes "dst". + * return: + * number of bits, either imputed classfully or specified with /CIDR, + * or -1 if some failure occurred (check errno). ENOENT means it was + * not a valid network specification. + * note: + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid loosing the + * actual last winsock error. So use macro ERRNO to fetch the + * errno this funtion sets when returning (-1), not SOCKERRNO. + * author: + * Paul Vixie (ISC), June 1996 + */ +int +ares_inet_net_pton(int af, const char *src, void *dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_net_pton_ipv4(src, dst, size)); + case AF_INET6: + return (inet_net_pton_ipv6(src, dst, size)); + default: + SET_ERRNO(EAFNOSUPPORT); + return (-1); + } +} + +#endif + +#ifndef HAVE_INET_PTON +int ares_inet_pton(int af, const char *src, void *dst) +{ + int result; + size_t size; + + if (af == AF_INET) + size = sizeof(struct in_addr); + else if (af == AF_INET6) + size = sizeof(struct ares_in6_addr); + else + { + SET_ERRNO(EAFNOSUPPORT); + return -1; + } + result = ares_inet_net_pton(af, src, dst, size); + if (result == -1 && ERRNO == ENOENT) + return 0; + return (result > -1 ? 1 : -1); +} +#endif diff --git a/deps/c-ares/inet_net_pton.h b/deps/c-ares/inet_net_pton.h new file mode 100644 index 00000000000..f5642a505e5 --- /dev/null +++ b/deps/c-ares/inet_net_pton.h @@ -0,0 +1,32 @@ +#ifndef __ARES_INET_NET_PTON_H +#define __ARES_INET_NET_PTON_H + +/* $Id$ */ + +/* Copyright (C) 2005 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifdef HAVE_INET_PTON +#define ares_inet_pton(x,y,z) inet_pton(x,y,z) +#else +int ares_inet_pton(int af, const char *src, void *dst); +#endif +#if defined(HAVE_INET_NET_PTON) && defined(HAVE_INET_NET_PTON_IPV6) +#define ares_inet_net_pton(w,x,y,z) inet_net_pton(w,x,y,z) +#else +int ares_inet_net_pton(int af, const char *src, void *dst, size_t size); +#endif + +#endif /* __ARES_INET_NET_PTON_H */ diff --git a/deps/c-ares/inet_ntop.c b/deps/c-ares/inet_ntop.c new file mode 100644 index 00000000000..3b35397804f --- /dev/null +++ b/deps/c-ares/inet_ntop.c @@ -0,0 +1,233 @@ +/* $Id$ */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "ares_setup.h" + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "ares.h" +#include "ares_ipv6.h" +#include "inet_ntop.h" + + +#ifndef HAVE_INET_NTOP + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); +static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * note: + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid loosing the + * actual last winsock error. So use macro ERRNO to fetch the + * errno this funtion sets when returning NULL, not SOCKERRNO. + * author: + * Paul Vixie, 1996. + */ +const char * +ares_inet_ntop(int af, const void *src, char *dst, size_t size) +{ + switch (af) + { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + SET_ERRNO(EAFNOSUPPORT); + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a unsigned char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, size_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const unsigned char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char *tp; + struct { + long base; + long len; + } best, cur; + unsigned long words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + + best.base = -1; + cur.base = -1; + best.len = 0; + cur.len = 0; + + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%lx", words[i])); + } + + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} +#endif + diff --git a/deps/c-ares/inet_ntop.h b/deps/c-ares/inet_ntop.h new file mode 100644 index 00000000000..ab9735e8099 --- /dev/null +++ b/deps/c-ares/inet_ntop.h @@ -0,0 +1,27 @@ +#ifndef __ARES_INET_NTOP_H +#define __ARES_INET_NTOP_H + +/* $Id$ */ + +/* Copyright (C) 2005 by Dominick Meglio + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifdef HAVE_INET_NTOP +#define ares_inet_ntop(w,x,y,z) inet_ntop(w,x,y,z) +#else +const char *ares_inet_ntop(int af, const void *src, char *dst, size_t size); +#endif + +#endif /* __ARES_INET_NTOP_H */ diff --git a/deps/c-ares/linux/ares_build.h b/deps/c-ares/linux/ares_build.h new file mode 100644 index 00000000000..ecceded29c8 --- /dev/null +++ b/deps/c-ares/linux/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 4 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/linux/ares_config.h b/deps/c-ares/linux/ares_config.h new file mode 100644 index 00000000000..a2cb7f293f9 --- /dev/null +++ b/deps/c-ares/linux/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 size_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 unsigned int + +/* Specifies the number of arguments to getservbyport_r */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#define GETSERVBYPORT_R_BUFSIZE 4096 + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#define HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +/* #undef HAVE_INET_NET_PTON */ + +/* Define to 1 if inet_net_pton supports IPv6. */ +/* #undef HAVE_INET_NET_PTON_IPV6 */ + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#define HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STROPTS_H 1 + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "i686-pc-linux-gnu" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV int + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/linux/ares_setup.h b/deps/c-ares/linux/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/linux/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/mac/ares_build.h b/deps/c-ares/mac/ares_build.h new file mode 100644 index 00000000000..ef4ded7b291 --- /dev/null +++ b/deps/c-ares/mac/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 8 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/mac/ares_config.h b/deps/c-ares/mac/ares_config.h new file mode 100644 index 00000000000..4114f05072d --- /dev/null +++ b/deps/c-ares/mac/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 socklen_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* Specifies the number of arguments to getservbyport_r */ +/* #undef GETSERVBYPORT_R_ARGS */ + +/* Specifies the size of the buffer to pass to getservbyport_r */ +/* #undef GETSERVBYPORT_R_BUFSIZE */ + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */ + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +/* #undef HAVE_GETSERVBYPORT_R */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if inet_net_pton supports IPv6. */ +#define HAVE_INET_NET_PTON_IPV6 1 + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +/* #undef HAVE_MSG_NOSIGNAL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "x86_64-apple-darwin10.3.0" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV ssize_t + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV ssize_t + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV ssize_t + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/mac/ares_setup.h b/deps/c-ares/mac/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/mac/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/nameser.h b/deps/c-ares/nameser.h new file mode 100644 index 00000000000..3d800964778 --- /dev/null +++ b/deps/c-ares/nameser.h @@ -0,0 +1,194 @@ +/* $Id$ */ + +#ifndef ARES_NAMESER_H +#define ARES_NAMESER_H + +/* header file provided by liren@vivisimo.com */ + +#ifndef HAVE_ARPA_NAMESER_H + +#define NS_PACKETSZ 512 /* maximum packet size */ +#define NS_MAXDNAME 256 /* maximum domain name */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ +#define NS_MAXLABEL 63 +#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ +#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ + +typedef enum __ns_class { + ns_c_invalid = 0, /* Cookie. */ + ns_c_in = 1, /* Internet. */ + ns_c_2 = 2, /* unallocated/unsupported. */ + ns_c_chaos = 3, /* MIT Chaos-net. */ + ns_c_hs = 4, /* MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /* for prereq. sections in update requests */ + ns_c_any = 255, /* Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_type { + ns_t_invalid = 0, /* Cookie. */ + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_apl = 42, /* Address prefix list (RFC3123) */ + ns_t_tkey = 249, /* Transaction key */ + ns_t_tsig = 250, /* Transaction signature. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ + ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +typedef enum __ns_opcode { + ns_o_query = 0, /* Standard query. */ + ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ + ns_o_status = 2, /* Name server status query (unsupported). */ + /* Opcode 3 is undefined/reserved. */ + ns_o_notify = 4, /* Zone change notification. */ + ns_o_update = 5, /* Zone update message. */ + ns_o_max = 6 +} ns_opcode; + +typedef enum __ns_rcode { + ns_r_noerror = 0, /* No error occurred. */ + ns_r_formerr = 1, /* Format error. */ + ns_r_servfail = 2, /* Server failure. */ + ns_r_nxdomain = 3, /* Name error. */ + ns_r_notimpl = 4, /* Unimplemented. */ + ns_r_refused = 5, /* Operation refused. */ + /* these are for BIND_UPDATE */ + ns_r_yxdomain = 6, /* Name exists */ + ns_r_yxrrset = 7, /* RRset exists */ + ns_r_nxrrset = 8, /* RRset does not exist */ + ns_r_notauth = 9, /* Not authoritative for zone */ + ns_r_notzone = 10, /* Zone of record different from zone section */ + ns_r_max = 11, + /* The following are TSIG extended errors */ + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +#endif /* HAVE_ARPA_NAMESER_H */ + +#ifndef HAVE_ARPA_NAMESER_COMPAT_H + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define QUERY ns_o_query + +#define SERVFAIL ns_r_servfail +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#undef NOERROR /* it seems this is already defined in winerror.h */ +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define NXDOMAIN ns_r_nxdomain + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#endif /* HAVE_ARPA_NAMESER_COMPAT_H */ + +#endif /* ARES_NAMESER_H */ diff --git a/deps/c-ares/setup_once.h b/deps/c-ares/setup_once.h new file mode 100644 index 00000000000..95722b2b733 --- /dev/null +++ b/deps/c-ares/setup_once.h @@ -0,0 +1,444 @@ +#ifndef __SETUP_ONCE_H +#define __SETUP_ONCE_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +/******************************************************************** + * NOTICE * + * ======== * + * * + * Content of header files lib/setup_once.h and ares/setup_once.h * + * must be kept in sync. Modify the other one if you change this. * + * * + ********************************************************************/ + + +/* + * Inclusion of common header files. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef NEED_MALLOC_H +#include +#endif + +#ifdef NEED_MEMORY_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#ifdef HAVE_TIME_H +#include +#endif +#endif + +#ifdef WIN32 +#include +#include +#endif + +#ifdef HAVE_STDBOOL_H +#include +#endif + + +/* + * Definition of timeval struct for platforms that don't have it. + */ + +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif + + +/* + * If we have the MSG_NOSIGNAL define, make sure we use + * it as the fourth argument of function send() + */ + +#ifdef HAVE_MSG_NOSIGNAL +#define SEND_4TH_ARG MSG_NOSIGNAL +#else +#define SEND_4TH_ARG 0 +#endif + + +#if defined(__minix) +/* Minix doesn't support recv on TCP sockets */ +#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \ + (RECV_TYPE_ARG2)(y), \ + (RECV_TYPE_ARG3)(z)) + +#elif defined(HAVE_RECV) +/* + * The definitions for the return type and arguments types + * of functions recv() and send() belong and come from the + * configuration file. Do not define them in any other place. + * + * HAVE_RECV is defined if you have a function named recv() + * which is used to read incoming data from sockets. If your + * function has another name then don't define HAVE_RECV. + * + * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2, + * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also + * be defined. + * + * HAVE_SEND is defined if you have a function named send() + * which is used to write outgoing data on a connected socket. + * If yours has another name then don't define HAVE_SEND. + * + * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2, + * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and + * SEND_TYPE_RETV must also be defined. + */ + +#if !defined(RECV_TYPE_ARG1) || \ + !defined(RECV_TYPE_ARG2) || \ + !defined(RECV_TYPE_ARG3) || \ + !defined(RECV_TYPE_ARG4) || \ + !defined(RECV_TYPE_RETV) + /* */ + Error Missing_definition_of_return_and_arguments_types_of_recv + /* */ +#else +#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ + (RECV_TYPE_ARG2)(y), \ + (RECV_TYPE_ARG3)(z), \ + (RECV_TYPE_ARG4)(0)) +#endif +#else /* HAVE_RECV */ +#ifndef sread + /* */ + Error Missing_definition_of_macro_sread + /* */ +#endif +#endif /* HAVE_RECV */ + + +#if defined(__minix) +/* Minix doesn't support send on TCP sockets */ +#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \ + (SEND_TYPE_ARG2)(y), \ + (SEND_TYPE_ARG3)(z)) + +#elif defined(HAVE_SEND) +#if !defined(SEND_TYPE_ARG1) || \ + !defined(SEND_QUAL_ARG2) || \ + !defined(SEND_TYPE_ARG2) || \ + !defined(SEND_TYPE_ARG3) || \ + !defined(SEND_TYPE_ARG4) || \ + !defined(SEND_TYPE_RETV) + /* */ + Error Missing_definition_of_return_and_arguments_types_of_send + /* */ +#else +#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ + (SEND_TYPE_ARG2)(y), \ + (SEND_TYPE_ARG3)(z), \ + (SEND_TYPE_ARG4)(SEND_4TH_ARG)) +#endif +#else /* HAVE_SEND */ +#ifndef swrite + /* */ + Error Missing_definition_of_macro_swrite + /* */ +#endif +#endif /* HAVE_SEND */ + + +#if 0 +#if defined(HAVE_RECVFROM) +/* + * Currently recvfrom is only used on udp sockets. + */ +#if !defined(RECVFROM_TYPE_ARG1) || \ + !defined(RECVFROM_TYPE_ARG2) || \ + !defined(RECVFROM_TYPE_ARG3) || \ + !defined(RECVFROM_TYPE_ARG4) || \ + !defined(RECVFROM_TYPE_ARG5) || \ + !defined(RECVFROM_TYPE_ARG6) || \ + !defined(RECVFROM_TYPE_RETV) + /* */ + Error Missing_definition_of_return_and_arguments_types_of_recvfrom + /* */ +#else +#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \ + (RECVFROM_TYPE_ARG2 *)(b), \ + (RECVFROM_TYPE_ARG3) (bl), \ + (RECVFROM_TYPE_ARG4) (0), \ + (RECVFROM_TYPE_ARG5 *)(f), \ + (RECVFROM_TYPE_ARG6 *)(fl)) +#endif +#else /* HAVE_RECVFROM */ +#ifndef sreadfrom + /* */ + Error Missing_definition_of_macro_sreadfrom + /* */ +#endif +#endif /* HAVE_RECVFROM */ + + +#ifdef RECVFROM_TYPE_ARG6_IS_VOID +# define RECVFROM_ARG6_T int +#else +# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6 +#endif +#endif /* if 0 */ + + +/* + * Function-like macro definition used to close a socket. + */ + +#if defined(HAVE_CLOSESOCKET) +# define sclose(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose(x) CloseSocket((x)) +#else +# define sclose(x) close((x)) +#endif + + +/* + * Uppercase macro versions of ANSI/ISO is*() functions/macros which + * avoid negative number inputs with argument byte codes > 127. + */ + +#define ISSPACE(x) (isspace((int) ((unsigned char)x))) +#define ISDIGIT(x) (isdigit((int) ((unsigned char)x))) +#define ISALNUM(x) (isalnum((int) ((unsigned char)x))) +#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) +#define ISGRAPH(x) (isgraph((int) ((unsigned char)x))) +#define ISALPHA(x) (isalpha((int) ((unsigned char)x))) +#define ISPRINT(x) (isprint((int) ((unsigned char)x))) +#define ISUPPER(x) (isupper((int) ((unsigned char)x))) +#define ISLOWER(x) (islower((int) ((unsigned char)x))) + +#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ + (((unsigned char)x) == '\t')) + + +/* + * Typedef to 'unsigned char' if bool is not an available 'typedefed' type. + */ + +#ifndef HAVE_BOOL_T +typedef unsigned char bool; +#define HAVE_BOOL_T +#endif + + +/* + * Default definition of uppercase TRUE and FALSE. + */ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + + +/* + * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. + */ + +#ifndef HAVE_SIG_ATOMIC_T +typedef int sig_atomic_t; +#define HAVE_SIG_ATOMIC_T +#endif + + +/* + * Convenience SIG_ATOMIC_T definition + */ + +#ifdef HAVE_SIG_ATOMIC_T_VOLATILE +#define SIG_ATOMIC_T static sig_atomic_t +#else +#define SIG_ATOMIC_T static volatile sig_atomic_t +#endif + + +/* + * Default return type for signal handlers. + */ + +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + + +/* + * Macro used to include code only in debug builds. + */ + +#ifdef DEBUGBUILD +#define DEBUGF(x) x +#else +#define DEBUGF(x) do { } while (0) +#endif + + +/* + * Macro used to include assertion code only in debug builds. + */ + +#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) +#define DEBUGASSERT(x) assert(x) +#else +#define DEBUGASSERT(x) do { } while (0) +#endif + + +/* + * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno + * (or equivalent) on this platform to hide platform details to code using it. + */ + +#ifdef USE_WINSOCK +#define SOCKERRNO ((int)WSAGetLastError()) +#define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) +#else +#define SOCKERRNO (errno) +#define SET_SOCKERRNO(x) (errno = (x)) +#endif + + +/* + * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno + * (or equivalent) on this platform to hide platform details to code using it. + */ + +#ifdef WIN32 +#define ERRNO ((int)GetLastError()) +#define SET_ERRNO(x) (SetLastError((DWORD)(x))) +#else +#define ERRNO (errno) +#define SET_ERRNO(x) (errno = (x)) +#endif + + +/* + * Portable error number symbolic names defined to Winsock error codes. + */ + +#ifdef USE_WINSOCK +#undef EBADF /* override definition in errno.h */ +#define EBADF WSAEBADF +#undef EINTR /* override definition in errno.h */ +#define EINTR WSAEINTR +#undef EINVAL /* override definition in errno.h */ +#define EINVAL WSAEINVAL +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#ifndef ENAMETOOLONG /* possible previous definition in errno.h */ +#define ENAMETOOLONG WSAENAMETOOLONG +#endif +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#ifndef ENOTEMPTY /* possible previous definition in errno.h */ +#define ENOTEMPTY WSAENOTEMPTY +#endif +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +#endif + + +/* + * Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid() + */ + +#if defined(__VMS) && \ + defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) +#define getpwuid __32_getpwuid +#endif + + +/* + * Macro argv_item_t hides platform details to code using it. + */ + +#ifdef __VMS +#define argv_item_t __char_ptr32 +#else +#define argv_item_t char * +#endif + + +/* + * We use this ZERO_NULL to avoid picky compiler warnings, + * when assigning a NULL pointer to a function pointer var. + */ + +#define ZERO_NULL 0 + + +#endif /* __SETUP_ONCE_H */ + diff --git a/deps/c-ares/solaris/ares_build.h b/deps/c-ares/solaris/ares_build.h new file mode 100644 index 00000000000..ecceded29c8 --- /dev/null +++ b/deps/c-ares/solaris/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 4 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/solaris/ares_config.h b/deps/c-ares/solaris/ares_config.h new file mode 100644 index 00000000000..0a0a54ecf8f --- /dev/null +++ b/deps/c-ares/solaris/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +/* #undef CARES_SYMBOL_HIDING */ + +/* Definition to make a library symbol externally visible. */ +/* #undef CARES_SYMBOL_SCOPE_EXTERN */ + +/* if a /etc/inet dir is being used */ +#define ETC_INET 1 + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 size_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* Specifies the number of arguments to getservbyport_r */ +#define GETSERVBYPORT_R_ARGS 5 + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#define GETSERVBYPORT_R_BUFSIZE 4096 + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#define HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +/* #undef HAVE_INET_NET_PTON */ + +/* Define to 1 if inet_net_pton supports IPv6. */ +/* #undef HAVE_INET_NET_PTON_IPV6 */ + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +/* #undef HAVE_IOCTL_FIONBIO */ + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +/* #undef HAVE_IOCTL_SIOCGIFADDR */ + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +/* #undef HAVE_MSG_NOSIGNAL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STROPTS_H 1 + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +#define NEED_REENTRANT 1 + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "i386-pc-solaris2.11" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 void + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG6_IS_VOID 1 + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV int + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/solaris/ares_setup.h b/deps/c-ares/solaris/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/solaris/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/windows_port.c b/deps/c-ares/windows_port.c new file mode 100644 index 00000000000..64096a5be02 --- /dev/null +++ b/deps/c-ares/windows_port.c @@ -0,0 +1,23 @@ +#include "ares_setup.h" + +/* $Id$ */ + +/* only do the following on windows + */ +#if (defined(WIN32) || defined(WATT32)) && !defined(MSDOS) + +#ifdef __WATCOMC__ +/* + * Watcom needs a DllMain() in order to initialise the clib startup code. + */ +BOOL +WINAPI DllMain (HINSTANCE hnd, DWORD reason, LPVOID reserved) +{ + (void) hnd; + (void) reason; + (void) reserved; + return (TRUE); +} +#endif + +#endif /* WIN32 builds only */ diff --git a/deps/c-ares/wscript b/deps/c-ares/wscript new file mode 100644 index 00000000000..5f49e7f30d1 --- /dev/null +++ b/deps/c-ares/wscript @@ -0,0 +1,31 @@ +import Options +import platform + +PLATFORM_IS_DARWIN = platform.platform().find('Darwin') == 0 +PLATFORM_IS_LINUX = platform.platform().find('Linux') == 0 +PLATFORM_IS_SOLARIS = platform.platform().find('Sun') == 0 + +def set_options(opt): + pass + +def configure(conf): + conf.env.append_value('CCFLAGS', ['-DHAVE_CONFIG_H=1']) + +def build(bld): + cares = bld.new_task_gen("cc") + cares.source = bld.path.ant_glob('*.c') + cares.target = 'cares' + cares.name = 'cares' + cares.includes = '.' + + if PLATFORM_IS_DARWIN: + cares.includes += ' ./mac/' + elif PLATFORM_IS_LINUX: + cares.includes += ' ./linux/' + elif PLATFORM_IS_SOLARIS: + cares.includes += ' ./solaris/' + + cares.install_path = None + if bld.env["USE_DEBUG"]: + cares.clone("debug"); + diff --git a/wscript b/wscript index 912cf20e9f3..e50fc021438 100644 --- a/wscript +++ b/wscript @@ -5,6 +5,7 @@ import sys, os, shutil from Utils import cmd_output from os.path import join, dirname, abspath from logging import fatal +import platform cwd = os.getcwd() VERSION="0.1.33" @@ -15,6 +16,10 @@ import js2c srcdir = '.' blddir = 'build' +PLATFORM_IS_DARWIN = platform.platform().find('Darwin') == 0 +PLATFORM_IS_LINUX = platform.platform().find('Linux') == 0 +PLATFORM_IS_SOLARIS = platform.platform().find('Sun') == 0 + def set_options(opt): # the gcc module provides a --debug-level option opt.tool_options('compiler_cxx') @@ -145,6 +150,8 @@ def configure(conf): conf.env.append_value("CCFLAGS", "-DEVCOM_HAVE_GNUTLS=1") conf.env.append_value("CXXFLAGS", "-DEVCOM_HAVE_GNUTLS=1") + conf.check(lib='rt', uselib_store='RT') + if sys.platform.startswith("sunos"): if not conf.check(lib='socket', uselib_store="SOCKET"): conf.fatal("Cannot find socket library") @@ -154,6 +161,7 @@ def configure(conf): conf.sub_config('deps/libeio') if not Options.options.system: conf.sub_config('deps/libev') + conf.sub_config('deps/c-ares') if sys.platform.startswith("sunos"): conf_subproject(conf, 'deps/udns', 'LIBS="-lsocket -lnsl" ./configure') else: @@ -163,6 +171,8 @@ def configure(conf): conf.fatal("Cannot find V8") if not conf.check(lib='ev', uselib_store='EV'): conf.fatal("Cannot find libev") + if not conf.check(lib='cares', uselib_store='CARES'): + conf.fatal("Cannot find c-ares") if not conf.check(lib='udns', uselib_store='UDNS'): conf.fatal("Cannot find udns") @@ -238,6 +248,7 @@ def build_udns(bld): bld.install_files('${PREFIX}/include/node/', 'deps/udns/udns.h') + def v8_cmd(bld, variant): scons = join(cwd, 'tools/scons/scons.py') deps_src = join(bld.path.abspath(),"deps") @@ -298,7 +309,7 @@ def build_v8(bld): def build(bld): if not bld.env["USE_SYSTEM"]: - bld.add_subdirs('deps/libeio deps/libev') + bld.add_subdirs('deps/libeio deps/libev deps/c-ares') build_udns(bld) build_v8(bld) else: @@ -420,15 +431,24 @@ def build(bld): src/ deps/v8/include deps/libev + deps/c-ares deps/udns deps/libeio deps/evcom deps/http_parser deps/coupling """ - node.add_objects = 'ev eio evcom http_parser coupling' + + if PLATFORM_IS_DARWIN: + node.includes += ' deps/c-ares/mac/' + elif PLATFORM_IS_LINUX: + node.includes += ' deps/c-ares/linux/' + elif PLATFORM_IS_SOLARIS: + node.includes += ' deps/c-ares/solaris/' + + node.add_objects = 'cares ev eio evcom http_parser coupling' node.uselib_local = '' - node.uselib = 'GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL' + node.uselib = 'RT GNUTLS GPGERROR UDNS CARES V8 EXECINFO DL KVM SOCKET NSL' else: node.includes = """ src/ @@ -439,7 +459,7 @@ def build(bld): """ node.add_objects = 'eio evcom http_parser coupling' node.uselib_local = 'eio' - node.uselib = 'EV GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL' + node.uselib = 'RT EV GNUTLS GPGERROR UDNS CARES V8 EXECINFO DL KVM SOCKET NSL' node.install_path = '${PREFIX}/lib' node.install_path = '${PREFIX}/bin' From dc1f4ebd4478b9fe32039d79a553fac01efafcf5 Mon Sep 17 00:00:00 2001 From: Krishna Rajendran Date: Tue, 6 Apr 2010 06:28:37 -0400 Subject: [PATCH 22/73] c-ares based dns module --- lib/dns_cares.js | 121 +++++++++ src/node.cc | 11 + src/node_cares.cc | 660 ++++++++++++++++++++++++++++++++++++++++++++++ src/node_cares.h | 16 ++ wscript | 1 + 5 files changed, 809 insertions(+) create mode 100644 lib/dns_cares.js create mode 100644 src/node_cares.cc create mode 100644 src/node_cares.h diff --git a/lib/dns_cares.js b/lib/dns_cares.js new file mode 100644 index 00000000000..f51702b440a --- /dev/null +++ b/lib/dns_cares.js @@ -0,0 +1,121 @@ +var dns = process.binding('cares'); + + +var watchers = {}; +var activeWatchers = {}; + + +var timer = new process.Timer(); + +timer.callback = function () { + for (var socket in activeWatchers) { + var s = parseInt(socket); + channel.processFD( watchers[socket].read ? s : dns.SOCKET_BAD + , watchers[socket].write ? s : dns.SOCKET_BAD + ); + } + updateTimer(); +} + + +function updateTimer() { + timer.stop(); + + for (var socket in activeWatchers) { // if !empty(activeWatchers) + var max = 20000; + var timeout = channel.timeout(max); + + timer.start(timeout, 0); + + return; + } +} + + +var channel = new dns.Channel({SOCK_STATE_CB: function (socket, read, write) { + var watcher; + + if (socket in watchers) { + watcher = watchers[socket].watcher; + } else { + watcher = new process.IOWatcher(); + watchers[socket] = { read: read + , write: write + , watcher: watcher + }; + + watcher.callback = function(read, write) { + channel.processFD( read ? socket : dns.SOCKET_BAD + , write ? socket : dns.SOCKET_BAD + ); + updateTimer(); + } + } + + watcher.set(socket, read == 1, write == 1); + + if (!(read || write)) { + watcher.stop(); + delete activeWatchers[socket]; + return; + } else { + watcher.start(); + activeWatchers[socket] = watcher; + } + + updateTimer(); +}}); + + + +exports.resolve = function (domain, type_, callback_) { + var type, callback; + if (typeof(type_) == 'string') { + type = type_; + callback = callback_; + } else { + type = 'A'; + callback = arguments[1]; + } + + var resolveFunc = resolveMap[type]; + + if (typeof(resolveFunc) == 'function') { + resolveFunc(domain, callback); + } else { + throw new Error('Unknown type "' + type + '"'); + } +} + + +exports.resolve4 = function(domain, callback) { channel.query(domain, dns.A, callback) }; +exports.resolve6 = function(domain, callback) { channel.query(domain, dns.AAAA, callback) }; +exports.resolveTxt = function(domain, callback) { channel.query(domain, dns.TXT, callback) }; +exports.resolveSrv = function(domain, callback) { channel.query(domain, dns.SRV, callback) }; +exports.reverse = function(domain, callback) { channel.query(domain, dns.PTR, callback) }; +exports.resolveNs = function(domain, callback) { channel.query(domain, dns.NS, callback) }; + + +var resolveMap = { + 'A' : exports.resolve4, + 'AAAA': exports.resolve6, + 'TXT' : exports.resolveTxt, + 'SRV' : exports.resolveSrv, + 'PTR' : exports.resolvePtr, + 'NS' : exports.resolveNs, +}; + +// ERROR CODES +exports.NODATA = dns.NODATA; +exports.FORMERR = dns.FORMERR; +exports.BADRESP = dns.BADRESP; +exports.NOTFOUND = dns.NOTFOUND; +exports.BADNAME = dns.BADNAME; +exports.TIMEOUT = dns.TIMEOUT; +exports.CONNREFUSED = dns.CONNREFUSED; +exports.NOMEM = dns.NOMEM; +exports.DESTRUCTION = dns.DESTRUCTION; + +exports.NOTIMP = dns.NOTIMP; +exports.EREFUSED = dns.EREFUSED; +exports.SERVFAIL = dns.SERVFAIL; diff --git a/src/node.cc b/src/node.cc index 3da989c00f7..412a666785d 100644 --- a/src/node.cc +++ b/src/node.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1194,6 +1195,15 @@ static Handle Binding(const Arguments& args) { binding_cache->Set(module, exports); } + } else if (!strcmp(*module_v, "cares")) { + if (binding_cache->Has(module)) { + exports = binding_cache->Get(module)->ToObject(); + } else { + exports = Object::New(); + Cares::Initialize(exports); + binding_cache->Set(module, exports); + } + } else if (!strcmp(*module_v, "fs")) { if (binding_cache->Has(module)) { exports = binding_cache->Get(module)->ToObject(); @@ -1266,6 +1276,7 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("buffer"), String::New(native_buffer)); exports->Set(String::New("child_process"),String::New(native_child_process)); exports->Set(String::New("dns"), String::New(native_dns)); + exports->Set(String::New("dns_cares"), String::New(native_dns_cares)); exports->Set(String::New("events"), String::New(native_events)); exports->Set(String::New("file"), String::New(native_file)); exports->Set(String::New("fs"), String::New(native_fs)); diff --git a/src/node_cares.cc b/src/node_cares.cc new file mode 100644 index 00000000000..cba62209cb3 --- /dev/null +++ b/src/node_cares.cc @@ -0,0 +1,660 @@ +#include + +#include +#include +#include + +#include +#include + + +namespace node { + +using namespace v8; + + +class Channel : public ObjectWrap { + public: + static void Initialize(Handle target); + + private: + static Persistent constructor_template; + + static Handle New(const Arguments& args); + static Handle Query(const Arguments& args); + static Handle GetHostByName(const Arguments& args); + static Handle GetHostByAddr(const Arguments& args); + static Handle Timeout(const Arguments& args); + static Handle ProcessFD(const Arguments& args); + + ares_channel channel; + + static void SockStateCb(void *data, int sock, int read, int write); + static void QueryCb(void *arg, int status, int timeouts, unsigned char* abuf, int alen); +}; + + +// To be passed to the QueryCb callback when a Query is finished. +// Holds a C callback to parse the response and the final JS callback +struct QueryArg { + typedef void (*ParseAnswerCb)(QueryArg*, unsigned char*, int); + Persistent js_cb; + ParseAnswerCb parse_cb; + + QueryArg(const Local &js_cb, ParseAnswerCb parse_cb) + : js_cb(Persistent::New(Local::Cast(js_cb))) + , parse_cb(parse_cb) {} + + ~QueryArg() { + js_cb.Dispose(); + } +}; + + +Persistent Channel::constructor_template; +static Persistent errno_symbol; +static Persistent priority_symbol; +static Persistent weight_symbol; +static Persistent port_symbol; +static Persistent name_symbol; +static Persistent callback_symbol; + + +void Cares::Initialize(Handle target) { + HandleScope scope; + + int r = ares_library_init(ARES_LIB_INIT_ALL); + if (0 != r) { + // TODO + // ThrowException(Exception::Error(String::New(ares_strerror(r)))); + assert(r == 0); + } + + + target->Set(String::NewSymbol("SOCKET_BAD"), Integer::New(ARES_SOCKET_BAD)); + + errno_symbol = NODE_PSYMBOL("errno"); + priority_symbol = NODE_PSYMBOL("priority"); + weight_symbol = NODE_PSYMBOL("weight"); + port_symbol = NODE_PSYMBOL("port"); + name_symbol = NODE_PSYMBOL("name"); + + target->Set(String::NewSymbol("AF_INET"), Integer::New(AF_INET)); + target->Set(String::NewSymbol("AF_INET6"), Integer::New(AF_INET6)); + + target->Set(String::NewSymbol("A"), Integer::New(ns_t_a)); + target->Set(String::NewSymbol("AAAA"), Integer::New(ns_t_aaaa)); + target->Set(String::NewSymbol("NS"), Integer::New(ns_t_ns)); + target->Set(String::NewSymbol("PTR"), Integer::New(ns_t_ptr)); + target->Set(String::NewSymbol("TXT"), Integer::New(ns_t_txt)); + target->Set(String::NewSymbol("SRV"), Integer::New(ns_t_srv)); + + target->Set(String::NewSymbol("NODATA"), Integer::New(ARES_ENODATA)); + target->Set(String::NewSymbol("FORMERR"), Integer::New(ARES_EFORMERR)); + target->Set(String::NewSymbol("BADRESP"), Integer::New(ARES_EBADRESP)); + target->Set(String::NewSymbol("NOTFOUND"), Integer::New(ARES_ENOTFOUND)); + target->Set(String::NewSymbol("BADNAME"), Integer::New(ARES_EBADNAME)); + target->Set(String::NewSymbol("TIMEOUT"), Integer::New(ARES_ETIMEOUT)); + target->Set(String::NewSymbol("CONNREFUSED"), Integer::New(ARES_ECONNREFUSED)); + target->Set(String::NewSymbol("NOMEM"), Integer::New(ARES_ENOMEM)); + target->Set(String::NewSymbol("DESTRUCTION"), Integer::New(ARES_EDESTRUCTION)); + + // Only occur if the ARES_FLAG_NOCHECKRESP flag was specified + target->Set(String::NewSymbol("NOTIMP"), Integer::New(ARES_ENOTIMP)); + target->Set(String::NewSymbol("EREFUSED"), Integer::New(ARES_EREFUSED)); + target->Set(String::NewSymbol("SERVFAIL"), Integer::New(ARES_ESERVFAIL)); + + Channel::Initialize(target); +} + + +static Local HostEntToAddresses(struct hostent* hostent) { + Local addresses = Array::New(); + + + char ip[INET6_ADDRSTRLEN]; + for (int i = 0; hostent->h_addr_list[i]; ++i) { + inet_ntop(hostent->h_addrtype, hostent->h_addr_list[i], ip, sizeof(ip)); + + Local address = String::New(ip); + addresses->Set(Integer::New(i), address); + } + + return addresses; +} + + +static Local HostEntToNames(struct hostent* hostent) { + Local names = Array::New(); + + for (int i = 0; hostent->h_aliases[i]; ++i) { + Local address = String::New(hostent->h_aliases[i]); + names->Set(Integer::New(i), address); + } + + return names; +} + + +static void ResolveError(Persistent &cb, int status) { + HandleScope scope; + + Local e = Exception::Error(String::NewSymbol(ares_strerror(status))); + Local obj = e->ToObject(); + obj->Set(errno_symbol, Integer::New(status)); + + TryCatch try_catch; + + cb->Call(Context::GetCurrent()->Global(), 1, &e); + + if (try_catch.HasCaught()) { + FatalException(try_catch); + } +} + + +static void HostByNameCb(void *data, + int status, + int timeouts, + struct hostent *hostent) { + HandleScope scope; + + Persistent *cb = cb_unwrap(data); + + if (status != ARES_SUCCESS) { + ResolveError(*cb, status); + cb_destroy(cb); + return; + } + + TryCatch try_catch; + + Local addresses = HostEntToAddresses(hostent); + + Local argv[2] = { Local::New(Null()), addresses}; + + (*cb)->Call(Context::GetCurrent()->Global(), 2, argv); + + if (try_catch.HasCaught()) { + FatalException(try_catch); + } + + cb_destroy(cb); +} + + +static void HostByAddrCb(void *data, + int status, + int timeouts, + struct hostent *hostent) { + HandleScope scope; + + Persistent *cb = cb_unwrap(data); + + if (status != ARES_SUCCESS) { + ResolveError(*cb, status); + cb_destroy(cb); + return; + } + + TryCatch try_catch; + + Local names = HostEntToNames(hostent); + + Local argv[2] = { Local::New(Null()), names }; + + (*cb)->Call(Context::GetCurrent()->Global(), 2, argv); + + if (try_catch.HasCaught()) { + FatalException(try_catch); + } + + cb_destroy(cb); +} + + +static void cb_call(Persistent &cb, int argc, Local *argv) { + TryCatch try_catch; + + cb->Call(Context::GetCurrent()->Global(), argc, argv); + + if (try_catch.HasCaught()) { + FatalException(try_catch); + } +} + + +static void ParseAnswerA(QueryArg *arg, unsigned char* abuf, int alen) { + HandleScope scope; + + hostent* host; + + int status = ares_parse_a_reply(abuf, alen, &host, NULL, NULL); + if (status != ARES_SUCCESS) { + ResolveError(arg->js_cb, status); + return; + } + + Local addresses = HostEntToAddresses(host); + ares_free_hostent(host); + + Local argv[2] = { Local::New(Null()), addresses }; + cb_call(arg->js_cb, 2, argv); +} + + +static void ParseAnswerAAAA(QueryArg *arg, unsigned char* abuf, int alen) { + HandleScope scope; + + hostent* host; + + int status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL); + if (status != ARES_SUCCESS) { + ResolveError(arg->js_cb, status); + return; + } + + Local addresses = HostEntToAddresses(host); + ares_free_hostent(host); + + Local argv[2] = { Local::New(Null()), addresses}; + cb_call(arg->js_cb, 2, argv); +} + + +static void ParseAnswerNS(QueryArg *arg, unsigned char* abuf, int alen) { + HandleScope scope; + + hostent* host; + + int status = ares_parse_ns_reply(abuf, alen, &host); + if (status != ARES_SUCCESS) { + ResolveError(arg->js_cb, status); + return; + } + + Local names = HostEntToNames(host); + ares_free_hostent(host); + + Local argv[2] = { Local::New(Null()), names }; + cb_call(arg->js_cb, 2, argv); +} + + +static void ParseAnswerSRV(QueryArg *arg, unsigned char* abuf, int alen) { + HandleScope scope; + + struct ares_srv_reply *srv_out; + + int status = ares_parse_srv_reply(abuf, alen, &srv_out); + if (status != ARES_SUCCESS) { + ResolveError(arg->js_cb, status); + return; + } + + Local srv_records = Array::New(); + + struct ares_srv_reply *current = srv_out; + for (int i = 0; current; ++i, current = current->next) { + Local srv = Object::New(); + + srv->Set(priority_symbol, Integer::New(current->priority)); + srv->Set(weight_symbol, Integer::New(current->weight)); + srv->Set(port_symbol, Integer::New(current->port)); + srv->Set(name_symbol, String::New(current->host)); + + srv_records->Set(Integer::New(i), srv); + } + ares_free_data(srv_out); + + Local argv[2] = { Local::New(Null()), srv_records }; + cb_call(arg->js_cb, 2, argv); +} + + +static void ParseAnswerTXT(QueryArg *arg, unsigned char* abuf, int alen) { + HandleScope scope; + + struct ares_txt_reply *txt_out; + + int status = ares_parse_txt_reply(abuf, alen, &txt_out); + if (status != ARES_SUCCESS) { + ResolveError(arg->js_cb, status); + return; + } + + Local txt_records = Array::New(); + + struct ares_txt_reply *current = txt_out; + for (int i = 0; current; ++i, current = current->next) { + Local txt = String::New(reinterpret_cast(current->txt)); + txt_records->Set(Integer::New(i), txt); + } + ares_free_data(txt_out); + + + Local argv[2] = { Local::New(Null()), txt_records }; + cb_call(arg->js_cb, 2, argv); +} + + +void Channel::QueryCb(void *arg, + int status, + int timeouts, + unsigned char* abuf, + int alen) { + QueryArg *query_arg = static_cast(arg); + + HandleScope scope; + + if (status != ARES_SUCCESS) { + ResolveError(query_arg->js_cb, status); + delete query_arg; + return; + } + + query_arg->parse_cb(query_arg, abuf, alen); + + delete query_arg; +} + + +void Channel::Initialize(Handle target) { + HandleScope scope; + + Local t = FunctionTemplate::New(Channel::New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Channel")); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getHostByName", Channel::GetHostByName); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "getHostByAddr", Channel::GetHostByAddr); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "query", Channel::Query); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "timeout", Channel::Timeout); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "processFD", Channel::ProcessFD); + + target->Set(String::NewSymbol("Channel"), constructor_template->GetFunction()); + + callback_symbol = NODE_PSYMBOL("callback"); +} + + +Handle Channel::New(const Arguments& args) { + HandleScope scope; + + struct ares_options options; + int optmask = 0; + + Channel *c = new Channel(); + c->Wrap(args.This()); + + if (args.Length() > 0) { + if(!args[0]->IsObject()) { + return ThrowException(Exception::TypeError( + String::New("Bad Options Argument"))); + } + + Local options_o = Local::Cast(args[0]); + Local keys = options_o->GetPropertyNames(); + int length = keys->Length(); + + for (int i = 0; i < length; ++i) { + Local opt = Local::Cast(keys->Get(Integer::New(i))); + + if (opt->Equals(String::New("SOCK_STATE_CB"))) { + c->handle_->Set(callback_symbol, options_o->Get(opt)); + options.sock_state_cb_data = c; + options.sock_state_cb = Channel::SockStateCb; + optmask |= ARES_OPT_SOCK_STATE_CB; + continue; + } + + return ThrowException(Exception::Error( + String::New("Unknown Option"))); + } + } + + ares_init_options(&c->channel, &options, optmask); + + return args.This(); +} + + +Handle Channel::Query(const Arguments& args) { + HandleScope scope; + Channel *c = ObjectWrap::Unwrap(args.Holder()); + assert(c); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError( + String::New("First argument must be a name"))); + } + + if (!args[1]->IsInt32()) { + return ThrowException(Exception::TypeError( + String::New("Second argument must be a query type"))); + } + + if (!args[2]->IsFunction()) { + return ThrowException(Exception::TypeError( + String::New("Third argument must be a callback"))); + } + + String::Utf8Value name(args[0]->ToString()); + int type = args[1]->Int32Value(); + QueryArg::ParseAnswerCb parse_cb; + + switch(type) { + case ns_t_a: + parse_cb = ParseAnswerA; + break; + + case ns_t_aaaa: + parse_cb = ParseAnswerAAAA; + break; + + case ns_t_ns: + parse_cb = ParseAnswerNS; + break; + + case ns_t_txt: + parse_cb = ParseAnswerTXT; + break; + + case ns_t_srv: + parse_cb = ParseAnswerSRV; + break; + + case ns_t_ptr: + + int length, family; + char address_b[sizeof(struct in6_addr)]; + + if (inet_pton(AF_INET, *name, &address_b) == 1) { + length = sizeof(struct in_addr); + family = AF_INET; + } else if (inet_pton(AF_INET6, *name, &address_b) == 1) { + length = sizeof(struct in6_addr); + family = AF_INET6; + } else { + return ThrowException(Exception::Error(String::New("Invalid IP address"))); + } + + ares_gethostbyaddr(c->channel, address_b, length, family, HostByAddrCb, cb_persist(args[2])); + + return Undefined(); + + default: + return ThrowException(Exception::Error( + String::New("Unsupported query type"))); + } + + QueryArg *query_arg = new QueryArg(args[2], parse_cb); + + ares_query(c->channel, *name, ns_c_in, type, QueryCb, query_arg); + + return Undefined(); +} + + +Handle Channel::GetHostByAddr(const Arguments& args) { + HandleScope scope; + Channel *c = ObjectWrap::Unwrap(args.Holder()); + assert(c); + + if (!args[0]->IsString()) { + return ThrowException(Exception::Error( + String::New("First argument must be a address"))); + } + + if (!args[1]->IsInt32()) { + return ThrowException(Exception::Error( + String::New("Second argument must be an address family"))); + } + + if (!args[2]->IsFunction()) { + return ThrowException(Exception::Error( + String::New("Third argument must be a callback"))); + } + + int family = args[1]->Int32Value(); + if (family != AF_INET6 && family != AF_INET) { + return ThrowException(Exception::Error( + String::New("Unsupported address family"))); + } + + String::Utf8Value address_s(args[0]->ToString()); + + char address_b[sizeof(struct in6_addr)]; + int r = inet_pton(family, *address_s, address_b); + if (r != 1) { + return ThrowException(Exception::Error( + String::New("Invalid network address"))); + } + + int length; + if (family == AF_INET6) + length = sizeof(struct in6_addr); + else + length = sizeof(struct in_addr); + + ares_gethostbyaddr(c->channel, address_b, length, family, HostByAddrCb, cb_persist(args[2])); + + return Undefined(); +} + + + +Handle Channel::GetHostByName(const Arguments& args) { + HandleScope scope; + Channel *c = ObjectWrap::Unwrap(args.Holder()); + assert(c); + + if (!args[0]->IsString()) { + return ThrowException(Exception::Error( + String::New("First argument must be a name"))); + } + + if (!args[1]->IsInt32()) { + return ThrowException(Exception::Error( + String::New("Second argument must be a family"))); + } + + if (!args[2]->IsFunction()) { + return ThrowException(Exception::Error( + String::New("Third argument must be a callback"))); + } + + int family = args[1]->Int32Value(); + if (family != AF_INET6 && family != AF_INET) { + return ThrowException(Exception::Error( + String::New("Unsupported address family"))); + } + + String::Utf8Value name(args[0]->ToString()); + + ares_gethostbyname(c->channel, *name, family, HostByNameCb, cb_persist(args[2])); + + return Undefined(); +} + + +Handle Channel::Timeout(const Arguments& args) { + HandleScope scope; + Channel *c = ObjectWrap::Unwrap(args.Holder()); + assert(c); + + if (!args[0]->IsInt32()) { + return ThrowException(Exception::Error( + String::New("First argument must be an integer number of milliseconds"))); + } + + struct timeval tvbuf, maxtv, *ret; + + int64_t time = args[0]->IntegerValue(); + maxtv.tv_sec = time/1000; + maxtv.tv_usec = (time % 1000) * 1000; + + ret = ares_timeout(c->channel, &maxtv, &tvbuf); + + return scope.Close(Integer::New(ret->tv_sec * 1000 + ret->tv_usec / 1000)); +} + + +Handle Channel::ProcessFD(const Arguments& args) { + HandleScope scope; + Channel *c = ObjectWrap::Unwrap(args.Holder()); + assert(c); + + int read_fd, write_fd; + + if (!args[0]->IsInt32()) { + return ThrowException(Exception::Error( + String::New("First argument must be a file descriptor or SOCKET_BAD"))); + } + + read_fd = args[0]->Int32Value(); + + if (args.Length() > 1) { + + if (!args[1]->IsInt32()) { + return ThrowException(Exception::Error( + String::New("Second argument must be a file descriptor or SOCKET_BAD"))); + } + write_fd = args[1]->Int32Value(); + + } else { + write_fd = ARES_SOCKET_BAD; + } + + ares_process_fd(c->channel, read_fd, write_fd); + + return Undefined(); +} + + +void Channel::SockStateCb(void *data, int sock, int read, int write) { + Channel *c = static_cast(data); + HandleScope scope; + + Local callback_v = c->handle_->Get(callback_symbol); + if (!callback_v->IsFunction()) return; + Local callback = Local::Cast(callback_v); + + Local argv[3]; + + argv[0] = Integer::New(sock); + argv[1] = Integer::New(read); + argv[2] = Integer::New(write); + + TryCatch try_catch; + + callback->Call(c->handle_, 3, argv); + + if (try_catch.HasCaught()) { + FatalException(try_catch); + } +} + + +} // namespace node diff --git a/src/node_cares.h b/src/node_cares.h new file mode 100644 index 00000000000..62244d493ca --- /dev/null +++ b/src/node_cares.h @@ -0,0 +1,16 @@ +#ifndef NODE_CARES_H_ +#define NODE_CARES_H_ + +#include +#include +#include + +namespace node { + +class Cares { + public: + static void Initialize(v8::Handle target); +}; + +} // namespace node +#endif // NODE_CARES_H_ diff --git a/wscript b/wscript index e50fc021438..a878a608459 100644 --- a/wscript +++ b/wscript @@ -416,6 +416,7 @@ def build(bld): src/node_child_process.cc src/node_constants.cc src/node_dns.cc + src/node_cares.cc src/node_events.cc src/node_file.cc src/node_http.cc From 96df65e88e010efe8f222110814bf862aaaea9c7 Mon Sep 17 00:00:00 2001 From: Krishna Rajendran Date: Tue, 6 Apr 2010 21:37:40 -0400 Subject: [PATCH 23/73] Make test-dns.js use dns_cares. --- test/disabled/test-dns.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/disabled/test-dns.js b/test/disabled/test-dns.js index f43ba5b8327..7121fffd45e 100644 --- a/test/disabled/test-dns.js +++ b/test/disabled/test-dns.js @@ -1,6 +1,7 @@ require("../common"); -var dns = require("dns"), +var dns = require("dns_cares"), + child_process = require("child_process"), sys = require("sys"); @@ -20,7 +21,7 @@ var hosts = ['example.com', 'example.org', '_xmpp-client._tcp.google.com', // SRV 'oakalynhall.co.uk']; // Multiple PTR replies -var records = ['A', 'AAAA', 'MX', 'TXT', 'SRV']; +var records = ['A', 'AAAA', 'TXT', 'SRV']; var i = hosts.length; while (i--) { @@ -32,7 +33,7 @@ while (i--) { "| sed -E 's/[[:space:]]+/ /g' | cut -d ' ' -f 5- " + "| sed -e 's/\\.$//'"; - sys.exec(hostCmd, checkDnsRecord(hosts[i], records[j])); + child_process.exec(hostCmd, checkDnsRecord(hosts[i], records[j])); } } @@ -61,7 +62,7 @@ function checkDnsRecord(host, record) { "| cut -d \" \" -f 5-" + "| sed -e 's/\\.$//'"; - sys.exec(reverseCmd, checkReverse(ip)); + child_process.exec(reverseCmd, checkReverse(ip)); } }); break; From 888a494ad814e73d8720bf9715916ec1397c3a49 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 01:45:20 -0700 Subject: [PATCH 24/73] Update LICENSE file with C-Ares info --- LICENSE | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LICENSE b/LICENSE index dfd91e7c4c0..7a3e96b90e2 100644 --- a/LICENSE +++ b/LICENSE @@ -19,6 +19,10 @@ are: Michael Tokarev . Released under the GNU Lesser General Public License version 2.1. + - C-Ares, an asynchronous DNS client, located at deps/c-ares. Copyright by + the Massachusetts Institute of Technology; authored by Greg Hudson, + Daniel Stenberg and others. Released under an MIT license. + Other external libraries are my own and all use the same license as Node. Node's license follows: From 067f4086b640c0a56dbb5174a69ba8777f054822 Mon Sep 17 00:00:00 2001 From: Vanilla Hsu Date: Thu, 8 Apr 2010 00:05:37 +0800 Subject: [PATCH 25/73] add c-ares' freebsd support. --- deps/c-ares/freebsd_amd64/ares_build.h | 112 ++++++ deps/c-ares/freebsd_amd64/ares_config.h | 513 ++++++++++++++++++++++++ deps/c-ares/freebsd_amd64/ares_setup.h | 198 +++++++++ deps/c-ares/freebsd_i386/ares_build.h | 112 ++++++ deps/c-ares/freebsd_i386/ares_config.h | 513 ++++++++++++++++++++++++ deps/c-ares/freebsd_i386/ares_setup.h | 198 +++++++++ deps/c-ares/wscript | 8 + wscript | 9 + 8 files changed, 1663 insertions(+) create mode 100644 deps/c-ares/freebsd_amd64/ares_build.h create mode 100644 deps/c-ares/freebsd_amd64/ares_config.h create mode 100644 deps/c-ares/freebsd_amd64/ares_setup.h create mode 100644 deps/c-ares/freebsd_i386/ares_build.h create mode 100644 deps/c-ares/freebsd_i386/ares_config.h create mode 100644 deps/c-ares/freebsd_i386/ares_setup.h diff --git a/deps/c-ares/freebsd_amd64/ares_build.h b/deps/c-ares/freebsd_amd64/ares_build.h new file mode 100644 index 00000000000..ef4ded7b291 --- /dev/null +++ b/deps/c-ares/freebsd_amd64/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 8 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/freebsd_amd64/ares_config.h b/deps/c-ares/freebsd_amd64/ares_config.h new file mode 100644 index 00000000000..0b04c4b614a --- /dev/null +++ b/deps/c-ares/freebsd_amd64/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 size_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* Specifies the number of arguments to getservbyport_r */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#define GETSERVBYPORT_R_BUFSIZE 4096 + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#define HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if inet_net_pton supports IPv6. */ +/* #undef HAVE_INET_NET_PTON_IPV6 */ + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#define HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "amd64-portbld-freebsd8.0" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV ssize_t + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV ssize_t + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV ssize_t + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/freebsd_amd64/ares_setup.h b/deps/c-ares/freebsd_amd64/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/freebsd_amd64/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/freebsd_i386/ares_build.h b/deps/c-ares/freebsd_i386/ares_build.h new file mode 100644 index 00000000000..ecceded29c8 --- /dev/null +++ b/deps/c-ares/freebsd_i386/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 4 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/freebsd_i386/ares_config.h b/deps/c-ares/freebsd_i386/ares_config.h new file mode 100644 index 00000000000..79508824daf --- /dev/null +++ b/deps/c-ares/freebsd_i386/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 size_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* Specifies the number of arguments to getservbyport_r */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#define GETSERVBYPORT_R_BUFSIZE 4096 + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#define HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if inet_net_pton supports IPv6. */ +/* #undef HAVE_INET_NET_PTON_IPV6 */ + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#define HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "i386-portbld-freebsd8.0" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV int + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV int + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV int + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/freebsd_i386/ares_setup.h b/deps/c-ares/freebsd_i386/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/freebsd_i386/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/wscript b/deps/c-ares/wscript index 5f49e7f30d1..a54be92fe36 100644 --- a/deps/c-ares/wscript +++ b/deps/c-ares/wscript @@ -4,6 +4,9 @@ import platform PLATFORM_IS_DARWIN = platform.platform().find('Darwin') == 0 PLATFORM_IS_LINUX = platform.platform().find('Linux') == 0 PLATFORM_IS_SOLARIS = platform.platform().find('Sun') == 0 +PLATFORM_IS_FREEBSD = platform.platform().find('FreeBSD') == 0 +MACHINE_IS_AMD64 = platform.machine().find('amd64') == 0 +MACHINE_IS_I386 = platform.machine().find('i386') == 0 def set_options(opt): pass @@ -24,6 +27,11 @@ def build(bld): cares.includes += ' ./linux/' elif PLATFORM_IS_SOLARIS: cares.includes += ' ./solaris/' + elif PLATFORM_IS_FREEBSD: + if MACHINE_IS_AMD64: + cares.includes += ' ./freebsd_amd64/' + elif MACHINE_IS_I386: + cares.includes += ' ./freebsd_i386/' cares.install_path = None if bld.env["USE_DEBUG"]: diff --git a/wscript b/wscript index a878a608459..176ce8d29e7 100644 --- a/wscript +++ b/wscript @@ -19,6 +19,9 @@ blddir = 'build' PLATFORM_IS_DARWIN = platform.platform().find('Darwin') == 0 PLATFORM_IS_LINUX = platform.platform().find('Linux') == 0 PLATFORM_IS_SOLARIS = platform.platform().find('Sun') == 0 +PLATFORM_IS_FREEBSD = platform.platform().find('FreeBSD') == 0 +MACHINE_IS_AMD64 = platform.machine().find('amd64') == 0 +MACHINE_IS_I386 = platform.machine().find('i386') == 0 def set_options(opt): # the gcc module provides a --debug-level option @@ -446,6 +449,12 @@ def build(bld): node.includes += ' deps/c-ares/linux/' elif PLATFORM_IS_SOLARIS: node.includes += ' deps/c-ares/solaris/' + elif PLATFORM_IS_FREEBSD: + if MACHINE_IS_AMD64: + node.includes += ' deps/c-ares/freebsd_amd64/' + elif MACHINE_IS_I386: + node.includes += ' deps/c-ares/freebsd_i386/' + node.add_objects = 'cares ev eio evcom http_parser coupling' node.uselib_local = '' From d36bb6536ed8e375dc5ff76a496e9e98c2c78765 Mon Sep 17 00:00:00 2001 From: Herbert Vojcik Date: Wed, 7 Apr 2010 20:07:57 +0200 Subject: [PATCH 26/73] Better require.async tests --- test/fixtures/a1.js | 1 + test/simple/test-module-loading.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 120000 test/fixtures/a1.js diff --git a/test/fixtures/a1.js b/test/fixtures/a1.js new file mode 120000 index 00000000000..44001cd1bca --- /dev/null +++ b/test/fixtures/a1.js @@ -0,0 +1 @@ +a.js \ No newline at end of file diff --git a/test/simple/test-module-loading.js b/test/simple/test-module-loading.js index 0011e136190..56515b8850c 100644 --- a/test/simple/test-module-loading.js +++ b/test/simple/test-module-loading.js @@ -58,9 +58,11 @@ try { assert.equal(require('path').dirname(__filename), __dirname); -require.async('../fixtures/a', function (err, a) { +var asyncRun = false; +require.async('../fixtures/a1', function (err, a) { if (err) throw err; assert.equal("A", a.A()); + asyncRun = true; }); debug('load custom file types with registerExtension'); @@ -99,5 +101,7 @@ process.addListener("exit", function () { assert.equal(true, errorThrown); + assert.equal(true, asyncRun); + puts("exit"); }); From eac3dc9d5f9be2228297a9524acbaceab6728dfa Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 11:25:55 -0700 Subject: [PATCH 27/73] Bugfix: net.js flushing, _doFlush typo --- lib/net.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net.js b/lib/net.js index 58da9f735f9..c143f77ca10 100644 --- a/lib/net.js +++ b/lib/net.js @@ -587,7 +587,7 @@ function doConnect (socket, port, host) { socket.resume(); socket.readable = true; socket.writable = true; - socket._writeWatcher.callback = socket._doFlush; + socket._writeWatcher.callback = _doFlush; socket.emit('connect'); } else if (errno != EINPROGRESS) { socket.forceClose(errnoException(errno, 'connect')); From 9ea8c9f2b0422ffaa4ff22722cfb20079c1a28eb Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 13:34:40 -0700 Subject: [PATCH 28/73] Clean up c-ares platform includes, add support for a few more --- .../ares_build.h | 0 .../{mac => darwin-x86_64}/ares_config.h | 0 .../ares_setup.h | 0 .../ares_build.h | 0 .../ares_config.h | 0 .../ares_setup.h | 0 .../{mac => freebsd-x86_64}/ares_build.h | 0 .../ares_config.h | 0 .../{linux => freebsd-x86_64}/ares_setup.h | 0 deps/c-ares/{linux => linux-x86}/ares_build.h | 0 .../c-ares/{linux => linux-x86}/ares_config.h | 0 deps/c-ares/{mac => linux-x86}/ares_setup.h | 0 .../{solaris => sunos-x86}/ares_build.h | 0 .../{solaris => sunos-x86}/ares_config.h | 0 .../{solaris => sunos-x86}/ares_setup.h | 0 deps/c-ares/wscript | 15 +----------- wscript | 23 ++++--------------- 17 files changed, 5 insertions(+), 33 deletions(-) rename deps/c-ares/{freebsd_amd64 => darwin-x86_64}/ares_build.h (100%) rename deps/c-ares/{mac => darwin-x86_64}/ares_config.h (100%) rename deps/c-ares/{freebsd_amd64 => darwin-x86_64}/ares_setup.h (100%) rename deps/c-ares/{freebsd_i386 => freebsd-x86}/ares_build.h (100%) rename deps/c-ares/{freebsd_i386 => freebsd-x86}/ares_config.h (100%) rename deps/c-ares/{freebsd_i386 => freebsd-x86}/ares_setup.h (100%) rename deps/c-ares/{mac => freebsd-x86_64}/ares_build.h (100%) rename deps/c-ares/{freebsd_amd64 => freebsd-x86_64}/ares_config.h (100%) rename deps/c-ares/{linux => freebsd-x86_64}/ares_setup.h (100%) rename deps/c-ares/{linux => linux-x86}/ares_build.h (100%) rename deps/c-ares/{linux => linux-x86}/ares_config.h (100%) rename deps/c-ares/{mac => linux-x86}/ares_setup.h (100%) rename deps/c-ares/{solaris => sunos-x86}/ares_build.h (100%) rename deps/c-ares/{solaris => sunos-x86}/ares_config.h (100%) rename deps/c-ares/{solaris => sunos-x86}/ares_setup.h (100%) diff --git a/deps/c-ares/freebsd_amd64/ares_build.h b/deps/c-ares/darwin-x86_64/ares_build.h similarity index 100% rename from deps/c-ares/freebsd_amd64/ares_build.h rename to deps/c-ares/darwin-x86_64/ares_build.h diff --git a/deps/c-ares/mac/ares_config.h b/deps/c-ares/darwin-x86_64/ares_config.h similarity index 100% rename from deps/c-ares/mac/ares_config.h rename to deps/c-ares/darwin-x86_64/ares_config.h diff --git a/deps/c-ares/freebsd_amd64/ares_setup.h b/deps/c-ares/darwin-x86_64/ares_setup.h similarity index 100% rename from deps/c-ares/freebsd_amd64/ares_setup.h rename to deps/c-ares/darwin-x86_64/ares_setup.h diff --git a/deps/c-ares/freebsd_i386/ares_build.h b/deps/c-ares/freebsd-x86/ares_build.h similarity index 100% rename from deps/c-ares/freebsd_i386/ares_build.h rename to deps/c-ares/freebsd-x86/ares_build.h diff --git a/deps/c-ares/freebsd_i386/ares_config.h b/deps/c-ares/freebsd-x86/ares_config.h similarity index 100% rename from deps/c-ares/freebsd_i386/ares_config.h rename to deps/c-ares/freebsd-x86/ares_config.h diff --git a/deps/c-ares/freebsd_i386/ares_setup.h b/deps/c-ares/freebsd-x86/ares_setup.h similarity index 100% rename from deps/c-ares/freebsd_i386/ares_setup.h rename to deps/c-ares/freebsd-x86/ares_setup.h diff --git a/deps/c-ares/mac/ares_build.h b/deps/c-ares/freebsd-x86_64/ares_build.h similarity index 100% rename from deps/c-ares/mac/ares_build.h rename to deps/c-ares/freebsd-x86_64/ares_build.h diff --git a/deps/c-ares/freebsd_amd64/ares_config.h b/deps/c-ares/freebsd-x86_64/ares_config.h similarity index 100% rename from deps/c-ares/freebsd_amd64/ares_config.h rename to deps/c-ares/freebsd-x86_64/ares_config.h diff --git a/deps/c-ares/linux/ares_setup.h b/deps/c-ares/freebsd-x86_64/ares_setup.h similarity index 100% rename from deps/c-ares/linux/ares_setup.h rename to deps/c-ares/freebsd-x86_64/ares_setup.h diff --git a/deps/c-ares/linux/ares_build.h b/deps/c-ares/linux-x86/ares_build.h similarity index 100% rename from deps/c-ares/linux/ares_build.h rename to deps/c-ares/linux-x86/ares_build.h diff --git a/deps/c-ares/linux/ares_config.h b/deps/c-ares/linux-x86/ares_config.h similarity index 100% rename from deps/c-ares/linux/ares_config.h rename to deps/c-ares/linux-x86/ares_config.h diff --git a/deps/c-ares/mac/ares_setup.h b/deps/c-ares/linux-x86/ares_setup.h similarity index 100% rename from deps/c-ares/mac/ares_setup.h rename to deps/c-ares/linux-x86/ares_setup.h diff --git a/deps/c-ares/solaris/ares_build.h b/deps/c-ares/sunos-x86/ares_build.h similarity index 100% rename from deps/c-ares/solaris/ares_build.h rename to deps/c-ares/sunos-x86/ares_build.h diff --git a/deps/c-ares/solaris/ares_config.h b/deps/c-ares/sunos-x86/ares_config.h similarity index 100% rename from deps/c-ares/solaris/ares_config.h rename to deps/c-ares/sunos-x86/ares_config.h diff --git a/deps/c-ares/solaris/ares_setup.h b/deps/c-ares/sunos-x86/ares_setup.h similarity index 100% rename from deps/c-ares/solaris/ares_setup.h rename to deps/c-ares/sunos-x86/ares_setup.h diff --git a/deps/c-ares/wscript b/deps/c-ares/wscript index a54be92fe36..9acc41ecfc3 100644 --- a/deps/c-ares/wscript +++ b/deps/c-ares/wscript @@ -19,20 +19,7 @@ def build(bld): cares.source = bld.path.ant_glob('*.c') cares.target = 'cares' cares.name = 'cares' - cares.includes = '.' - - if PLATFORM_IS_DARWIN: - cares.includes += ' ./mac/' - elif PLATFORM_IS_LINUX: - cares.includes += ' ./linux/' - elif PLATFORM_IS_SOLARIS: - cares.includes += ' ./solaris/' - elif PLATFORM_IS_FREEBSD: - if MACHINE_IS_AMD64: - cares.includes += ' ./freebsd_amd64/' - elif MACHINE_IS_I386: - cares.includes += ' ./freebsd_i386/' - + cares.includes = '. ./' + bld.env['DEST_OS'] + '-' + bld.env['DEST_CPU'] cares.install_path = None if bld.env["USE_DEBUG"]: cares.clone("debug"); diff --git a/wscript b/wscript index 176ce8d29e7..1b5f10722eb 100644 --- a/wscript +++ b/wscript @@ -5,7 +5,6 @@ import sys, os, shutil from Utils import cmd_output from os.path import join, dirname, abspath from logging import fatal -import platform cwd = os.getcwd() VERSION="0.1.33" @@ -16,13 +15,6 @@ import js2c srcdir = '.' blddir = 'build' -PLATFORM_IS_DARWIN = platform.platform().find('Darwin') == 0 -PLATFORM_IS_LINUX = platform.platform().find('Linux') == 0 -PLATFORM_IS_SOLARIS = platform.platform().find('Sun') == 0 -PLATFORM_IS_FREEBSD = platform.platform().find('FreeBSD') == 0 -MACHINE_IS_AMD64 = platform.machine().find('amd64') == 0 -MACHINE_IS_I386 = platform.machine().find('i386') == 0 - def set_options(opt): # the gcc module provides a --debug-level option opt.tool_options('compiler_cxx') @@ -311,6 +303,9 @@ def build_v8(bld): bld.install_files('${PREFIX}/include/node/', 'deps/v8/include/*.h') def build(bld): + print "DEST_OS: " + bld.env['DEST_OS'] + print "DEST_CPU: " + bld.env['DEST_CPU'] + if not bld.env["USE_SYSTEM"]: bld.add_subdirs('deps/libeio deps/libev deps/c-ares') build_udns(bld) @@ -443,17 +438,7 @@ def build(bld): deps/coupling """ - if PLATFORM_IS_DARWIN: - node.includes += ' deps/c-ares/mac/' - elif PLATFORM_IS_LINUX: - node.includes += ' deps/c-ares/linux/' - elif PLATFORM_IS_SOLARIS: - node.includes += ' deps/c-ares/solaris/' - elif PLATFORM_IS_FREEBSD: - if MACHINE_IS_AMD64: - node.includes += ' deps/c-ares/freebsd_amd64/' - elif MACHINE_IS_I386: - node.includes += ' deps/c-ares/freebsd_i386/' + node.includes += ' deps/c-ares/' + bld.env['DEST_OS'] + '-' + bld.env['DEST_CPU'] node.add_objects = 'cares ev eio evcom http_parser coupling' From f56ff0de9280a1371a319e368380043bd8c8fe6c Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 13:39:11 -0700 Subject: [PATCH 29/73] Add darwin-x86, linux-x86_64 c-ares headers --- deps/c-ares/darwin-x86/ares_build.h | 112 ++++++ deps/c-ares/darwin-x86/ares_config.h | 513 +++++++++++++++++++++++++ deps/c-ares/darwin-x86/ares_setup.h | 198 ++++++++++ deps/c-ares/linux-x86_64/ares_build.h | 112 ++++++ deps/c-ares/linux-x86_64/ares_config.h | 513 +++++++++++++++++++++++++ deps/c-ares/linux-x86_64/ares_setup.h | 198 ++++++++++ 6 files changed, 1646 insertions(+) create mode 100644 deps/c-ares/darwin-x86/ares_build.h create mode 100644 deps/c-ares/darwin-x86/ares_config.h create mode 100644 deps/c-ares/darwin-x86/ares_setup.h create mode 100644 deps/c-ares/linux-x86_64/ares_build.h create mode 100644 deps/c-ares/linux-x86_64/ares_config.h create mode 100644 deps/c-ares/linux-x86_64/ares_setup.h diff --git a/deps/c-ares/darwin-x86/ares_build.h b/deps/c-ares/darwin-x86/ares_build.h new file mode 100644 index 00000000000..ecceded29c8 --- /dev/null +++ b/deps/c-ares/darwin-x86/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 4 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/darwin-x86/ares_config.h b/deps/c-ares/darwin-x86/ares_config.h new file mode 100644 index 00000000000..77b6d4a3c2f --- /dev/null +++ b/deps/c-ares/darwin-x86/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 socklen_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 int + +/* Specifies the number of arguments to getservbyport_r */ +/* #undef GETSERVBYPORT_R_ARGS */ + +/* Specifies the size of the buffer to pass to getservbyport_r */ +/* #undef GETSERVBYPORT_R_BUFSIZE */ + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */ + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +/* #undef HAVE_GETSERVBYPORT_R */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +#define HAVE_INET_NET_PTON 1 + +/* Define to 1 if inet_net_pton supports IPv6. */ +#define HAVE_INET_NET_PTON_IPV6 1 + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +/* #undef HAVE_MSG_NOSIGNAL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "i386-apple-darwin9.8.0" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV ssize_t + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV ssize_t + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV ssize_t + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/darwin-x86/ares_setup.h b/deps/c-ares/darwin-x86/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/darwin-x86/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ diff --git a/deps/c-ares/linux-x86_64/ares_build.h b/deps/c-ares/linux-x86_64/ares_build.h new file mode 100644 index 00000000000..ef4ded7b291 --- /dev/null +++ b/deps/c-ares/linux-x86_64/ares_build.h @@ -0,0 +1,112 @@ +/* ares_build.h. Generated from ares_build.h.in by configure. */ +#ifndef __CARES_BUILD_H +#define __CARES_BUILD_H + +/* $Id$ */ + +/* Copyright (C) 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * c-ares library user nor by the c-ares library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the c-ares development + * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/ + * + * This header file shall only export symbols which are 'cares' or 'CARES' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file ares_build.h.in or ares_build.h, + * this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed ares_build.h file with one that is suitable + * and specific to the library being configured and built, which is generated + * from the ares_build.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CARES_SIZEOF_LONG +# error "CARES_SIZEOF_LONG shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_LONG_already_defined +#endif + +#ifdef CARES_TYPEOF_ARES_SOCKLEN_T +# error "CARES_TYPEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_TYPEOF_ARES_SOCKLEN_T_already_defined +#endif + +#ifdef CARES_SIZEOF_ARES_SOCKLEN_T +# error "CARES_SIZEOF_ARES_SOCKLEN_T shall not be defined except in ares_build.h" + Error Compilation_aborted_CARES_SIZEOF_ARES_SOCKLEN_T_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CARES_PULL_WS2TCPIP_H */ +#ifdef CARES_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CARES_PULL_SYS_TYPES_H 1 +#ifdef CARES_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CARES_PULL_SYS_SOCKET_H 1 +#ifdef CARES_PULL_SYS_SOCKET_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CARES_SIZEOF_LONG 8 + +/* Integral data type used for ares_socklen_t. */ +#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t + +/* The size of `ares_socklen_t', as computed by sizeof. */ +#define CARES_SIZEOF_ARES_SOCKLEN_T 4 + +/* Data type definition of ares_socklen_t. */ +typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t; + +#endif /* __CARES_BUILD_H */ diff --git a/deps/c-ares/linux-x86_64/ares_config.h b/deps/c-ares/linux-x86_64/ares_config.h new file mode 100644 index 00000000000..dd025a95a68 --- /dev/null +++ b/deps/c-ares/linux-x86_64/ares_config.h @@ -0,0 +1,513 @@ +/* ares_config.h. Generated from ares_config.h.in by configure. */ +/* ares_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* define this if ares is built for a big endian system */ +/* #undef ARES_BIG_ENDIAN */ + +/* when building as static part of libcurl */ +/* #undef BUILDING_LIBCURL */ + +/* when building c-ares library */ +/* #undef CARES_BUILDING_LIBRARY */ + +/* when not building a shared library */ +/* #undef CARES_STATICLIB */ + +/* Define to 1 to enable hiding of library internal symbols. */ +#define CARES_SYMBOL_HIDING 1 + +/* Definition to make a library symbol externally visible. */ +#define CARES_SYMBOL_SCOPE_EXTERN __attribute__ ((visibility ("default"))) + +/* if a /etc/inet dir is being used */ +/* #undef ETC_INET */ + +/* Define to the type qualifier of arg 1 for getnameinfo. */ +#define GETNAMEINFO_QUAL_ARG1 const + +/* Define to the type of arg 1 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG1 struct sockaddr * + +/* Define to the type of arg 2 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG2 socklen_t + +/* Define to the type of args 4 and 6 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG46 socklen_t + +/* Define to the type of arg 7 for getnameinfo. */ +#define GETNAMEINFO_TYPE_ARG7 unsigned int + +/* Specifies the number of arguments to getservbyport_r */ +#define GETSERVBYPORT_R_ARGS 6 + +/* Specifies the size of the buffer to pass to getservbyport_r */ +#define GETSERVBYPORT_R_BUFSIZE 4096 + +/* Define to 1 if you have AF_INET6. */ +#define HAVE_AF_INET6 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_COMPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bitncmp' function. */ +/* #undef HAVE_BITNCMP */ + +/* Define to 1 if bool is an available type. */ +#define HAVE_BOOL_T 1 + +/* Define to 1 if you have the clock_gettime function and monotonic timer. */ +#define HAVE_CLOCK_GETTIME_MONOTONIC 1 + +/* Define to 1 if you have the closesocket function. */ +/* #undef HAVE_CLOSESOCKET */ + +/* Define to 1 if you have the CloseSocket camel case function. */ +/* #undef HAVE_CLOSESOCKET_CAMEL */ + +/* Define to 1 if you have the connect function. */ +#define HAVE_CONNECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the fcntl function. */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */ +#define HAVE_FCNTL_O_NONBLOCK 1 + +/* Define to 1 if you have the freeaddrinfo function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define to 1 if you have a working getaddrinfo function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#define HAVE_GETADDRINFO_THREADSAFE 1 + +/* Define to 1 if you have the gethostbyaddr function. */ +#define HAVE_GETHOSTBYADDR 1 + +/* Define to 1 if you have the gethostbyname function. */ +#define HAVE_GETHOSTBYNAME 1 + +/* Define to 1 if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the getnameinfo function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the getservbyport_r function. */ +#define HAVE_GETSERVBYPORT_R 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `if_indextoname' function. */ +#define HAVE_IF_INDEXTONAME 1 + +/* Define to 1 if you have the `inet_net_pton' function. */ +/* #undef HAVE_INET_NET_PTON */ + +/* Define to 1 if inet_net_pton supports IPv6. */ +/* #undef HAVE_INET_NET_PTON_IPV6 */ + +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the ioctl function. */ +#define HAVE_IOCTL 1 + +/* Define to 1 if you have the ioctlsocket function. */ +/* #undef HAVE_IOCTLSOCKET */ + +/* Define to 1 if you have the IoctlSocket camel case function. */ +/* #undef HAVE_IOCTLSOCKET_CAMEL */ + +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. + */ +/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ + +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */ +/* #undef HAVE_IOCTLSOCKET_FIONBIO */ + +/* Define to 1 if you have a working ioctl FIONBIO function. */ +#define HAVE_IOCTL_FIONBIO 1 + +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ +#define HAVE_IOCTL_SIOCGIFADDR 1 + +/* Define to 1 if you have the `resolve' library (-lresolve). */ +/* #undef HAVE_LIBRESOLVE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* if your compiler supports LL */ +#define HAVE_LL 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the malloc.h header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the memory.h header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the MSG_NOSIGNAL flag. */ +#define HAVE_MSG_NOSIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have PF_INET6. */ +#define HAVE_PF_INET6 1 + +/* Define to 1 if you have the recv function. */ +#define HAVE_RECV 1 + +/* Define to 1 if you have the recvfrom function. */ +#define HAVE_RECVFROM 1 + +/* Define to 1 if you have the send function. */ +#define HAVE_SEND 1 + +/* Define to 1 if you have the setsockopt function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ +/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if sig_atomic_t is an available typedef. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* Define to 1 if sig_atomic_t is already defined as volatile. */ +/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ + +/* Define to 1 if your struct sockaddr_in6 has sin6_scope_id. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* Define to 1 if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the strncmpi function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STROPTS_H 1 + +/* Define to 1 if you have struct addrinfo. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if you have struct in6_addr. */ +#define HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if you have struct sockaddr_in6. */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 + +/* if struct sockaddr_storage is defined */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if you have the timeval struct. */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the windows.h header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the winsock2.h header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the winsock.h header file. */ +/* #undef HAVE_WINSOCK_H */ + +/* Define to 1 if you have the writev function. */ +#define HAVE_WRITEV 1 + +/* Define to 1 if you have the ws2tcpip.h header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if you are building a native Windows target. */ +/* #undef NATIVE_WINDOWS */ + +/* Define to 1 if you need the malloc.h header file even with stdlib.h */ +/* #undef NEED_MALLOC_H */ + +/* Define to 1 if you need the memory.h header file even with stdlib.h */ +/* #undef NEED_MEMORY_H */ + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ +/* #undef NEED_THREAD_SAFE */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* cpu-machine-OS */ +#define OS "x86_64-unknown-linux-gnu" + +/* Name of package */ +#define PACKAGE "c-ares" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "c-ares mailing list => http://cool.haxx.se/mailman/listinfo/c-ares" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "c-ares" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "c-ares 1.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "c-ares" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.1" + +/* a suitable file/device to read random data from */ +#define RANDOM_FILE "/dev/urandom" + +/* Define to the type of arg 1 for recvfrom. */ +#define RECVFROM_TYPE_ARG1 int + +/* Define to the type pointed by arg 2 for recvfrom. */ +#define RECVFROM_TYPE_ARG2 void + +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ +#define RECVFROM_TYPE_ARG2_IS_VOID 1 + +/* Define to the type of arg 3 for recvfrom. */ +#define RECVFROM_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recvfrom. */ +#define RECVFROM_TYPE_ARG4 int + +/* Define to the type pointed by arg 5 for recvfrom. */ +#define RECVFROM_TYPE_ARG5 struct sockaddr + +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ + +/* Define to the type pointed by arg 6 for recvfrom. */ +#define RECVFROM_TYPE_ARG6 socklen_t + +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ +/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ + +/* Define to the function return type for recvfrom. */ +#define RECVFROM_TYPE_RETV ssize_t + +/* Define to the type of arg 1 for recv. */ +#define RECV_TYPE_ARG1 int + +/* Define to the type of arg 2 for recv. */ +#define RECV_TYPE_ARG2 void * + +/* Define to the type of arg 3 for recv. */ +#define RECV_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for recv. */ +#define RECV_TYPE_ARG4 int + +/* Define to the function return type for recv. */ +#define RECV_TYPE_RETV ssize_t + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the type qualifier of arg 2 for send. */ +#define SEND_QUAL_ARG2 const + +/* Define to the type of arg 1 for send. */ +#define SEND_TYPE_ARG1 int + +/* Define to the type of arg 2 for send. */ +#define SEND_TYPE_ARG2 void * + +/* Define to the type of arg 3 for send. */ +#define SEND_TYPE_ARG3 size_t + +/* Define to the type of arg 4 for send. */ +#define SEND_TYPE_ARG4 int + +/* Define to the function return type for send. */ +#define SEND_TYPE_RETV ssize_t + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `struct in6_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN6_ADDR 16 + +/* The size of `struct in_addr', as computed by sizeof. */ +#define SIZEOF_STRUCT_IN_ADDR 4 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to disable non-blocking sockets. */ +/* #undef USE_BLOCKING_SOCKETS */ + +/* Version number of package */ +#define VERSION "1.7.1" + +/* Define to avoid automatic inclusion of winsock.h */ +/* #undef WIN32_LEAN_AND_MEAN */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if OS is AIX. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Type to use in place of in_addr_t when system does not provide it. */ +/* #undef in_addr_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* the signed version of size_t */ +/* #undef ssize_t */ diff --git a/deps/c-ares/linux-x86_64/ares_setup.h b/deps/c-ares/linux-x86_64/ares_setup.h new file mode 100644 index 00000000000..ce81b1fa3fd --- /dev/null +++ b/deps/c-ares/linux-x86_64/ares_setup.h @@ -0,0 +1,198 @@ +#ifndef HEADER_CARES_SETUP_H +#define HEADER_CARES_SETUP_H + +/* $Id$ */ + +/* Copyright (C) 2004 - 2009 by Daniel Stenberg et al + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Include configuration script results or hand-crafted + * configuration file for platforms which lack config tool. + */ + +#ifdef HAVE_CONFIG_H +#include "ares_config.h" +#else + +#ifdef WIN32 +#include "config-win32.h" +#endif + +#endif /* HAVE_CONFIG_H */ + +/* ================================================================ */ +/* Definition of preprocessor macros/symbols which modify compiler */ +/* behaviour or generated code characteristics must be done here, */ +/* as appropriate, before any system header file is included. It is */ +/* also possible to have them defined in the config file included */ +/* before this point. As a result of all this we frown inclusion of */ +/* system header files in our config files, avoid this at any cost. */ +/* ================================================================ */ + +/* + * AIX 4.3 and newer needs _THREAD_SAFE defined to build + * proper reentrant code. Others may also need it. + */ + +#ifdef NEED_THREAD_SAFE +# ifndef _THREAD_SAFE +# define _THREAD_SAFE +# endif +#endif + +/* + * Tru64 needs _REENTRANT set for a few function prototypes and + * things to appear in the system header files. Unixware needs it + * to build proper reentrant code. Others may also need it. + */ + +#ifdef NEED_REENTRANT +# ifndef _REENTRANT +# define _REENTRANT +# endif +#endif + +/* ================================================================ */ +/* If you need to include a system header file for your platform, */ +/* please, do it beyond the point further indicated in this file. */ +/* ================================================================ */ + +/* + * c-ares external interface definitions are also used internally, + * and might also include required system header files to define them. + */ + +#include + +/* + * Compile time sanity checks must also be done when building the library. + */ + +#include + +/* ================================================================= */ +/* No system header file shall be included in this file before this */ +/* point. The only allowed ones are those included from ares_build.h */ +/* ================================================================= */ + +/* + * Include header files for windows builds before redefining anything. + * Use this preproessor block only to include or exclude windows.h, + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * to any other further and independent block. Under Cygwin things work + * just as under linux (e.g. ) and the winsock headers should + * never be included when __CYGWIN__ is defined. configure script takes + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + */ + +#ifdef HAVE_WINDOWS_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# ifdef HAVE_WINSOCK2_H +# include +# ifdef HAVE_WS2TCPIP_H +# include +# endif +# else +# ifdef HAVE_WINSOCK_H +# include +# endif +# endif +#endif + +/* + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else + * define USE_WINSOCK to 1 if we have and use WINSOCK API, else + * undefine USE_WINSOCK. + */ + +#undef USE_WINSOCK + +#ifdef HAVE_WINSOCK2_H +# define USE_WINSOCK 2 +#else +# ifdef HAVE_WINSOCK_H +# define USE_WINSOCK 1 +# endif +#endif + +/* + * Work-arounds for systems without configure support + */ + +#ifndef HAVE_CONFIG_H + +#if !defined(HAVE_SYS_TIME_H) && !defined(_MSC_VER) && !defined(__WATCOMC__) +#define HAVE_SYS_TIME_H +#endif + +#if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) +#define HAVE_UNISTD_H 1 +#endif + +#if !defined(HAVE_SYS_UIO_H) && !defined(WIN32) && !defined(MSDOS) +#define HAVE_SYS_UIO_H +#endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef __POCC__ +# include +# include +# define ESRCH 3 +#endif + +/* + * Recent autoconf versions define these symbols in ares_config.h. We don't + * want them (since they collide with the libcurl ones when we build + * --enable-debug) so we undef them again here. + */ + +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef VERSION +#undef PACKAGE + +/* IPv6 compatibility */ +#if !defined(HAVE_AF_INET6) +#if defined(HAVE_PF_INET6) +#define AF_INET6 PF_INET6 +#else +#define AF_INET6 AF_MAX+1 +#endif +#endif + +/* + * Include macros and defines that should only be processed once. + */ + +#ifndef __SETUP_ONCE_H +#include "setup_once.h" +#endif + +#endif /* HEADER_CARES_SETUP_H */ From f13e2f96e40ecdd6e76854508c3b0cad6bcd1a8d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 15:37:08 -0700 Subject: [PATCH 30/73] Add a simple c-ares test, dns_cares.lookup() for easy resolv --- lib/dns_cares.js | 23 +++++++++++++++++++++++ test/simple/test-c-ares.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/simple/test-c-ares.js diff --git a/lib/dns_cares.js b/lib/dns_cares.js index f51702b440a..fbb10d3fb2e 100644 --- a/lib/dns_cares.js +++ b/lib/dns_cares.js @@ -1,4 +1,5 @@ var dns = process.binding('cares'); +var sys = require('sys'); // TODO remove me var watchers = {}; @@ -88,6 +89,28 @@ exports.resolve = function (domain, type_, callback_) { } +exports.getHostByName = function (domain, callback) { + channel.getHostByName(domain, dns.AF_INET, callback); +}; + +// Easy DNS A/AAAA look up +exports.lookup = function (domain, callback) { + channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { + if (domains4 && domains4.length) { + callback(null, domains4[0], 4); + } else { + channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { + if (domains6 && domains6.length) { + callback(null, domains6[0], 6); + } else { + callback(err, []); + } + }); + } + }); +}; + + exports.resolve4 = function(domain, callback) { channel.query(domain, dns.A, callback) }; exports.resolve6 = function(domain, callback) { channel.query(domain, dns.AAAA, callback) }; exports.resolveTxt = function(domain, callback) { channel.query(domain, dns.TXT, callback) }; diff --git a/test/simple/test-c-ares.js b/test/simple/test-c-ares.js new file mode 100644 index 00000000000..683babc4747 --- /dev/null +++ b/test/simple/test-c-ares.js @@ -0,0 +1,28 @@ +require('../common'); + +var dns = require("dns_cares"); + + +// Try resolution without callback + +dns.getHostByName('localhost', function (error, result) { + p(result); + assert.deepEqual(['127.0.0.1'], result); +}); + +dns.getHostByName('127.0.0.1', function (error, result) { + p(result); + assert.deepEqual(['127.0.0.1'], result); +}); + +dns.lookup('127.0.0.1', function (error, result, ipVersion) { + assert.deepEqual('127.0.0.1', result); + assert.equal(4, ipVersion); +}); + +dns.lookup('ipv6.google.com', function (error, result, ipVersion) { + if (error) throw error; + p(arguments); + //assert.equal('string', typeof result); + assert.equal(6, ipVersion); +}); From 8f671041a52dd28fa473762b637b03c402f0db04 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 16:04:33 -0700 Subject: [PATCH 31/73] Check for ip address in dns_cares.lookup --- lib/dns_cares.js | 37 ++++++++++++++++++++++++------------- src/node_cares.cc | 29 +++++++++++++++++++++++++++++ test/simple/test-c-ares.js | 20 +++++++++++++++----- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/lib/dns_cares.js b/lib/dns_cares.js index fbb10d3fb2e..11caa3a067b 100644 --- a/lib/dns_cares.js +++ b/lib/dns_cares.js @@ -95,19 +95,30 @@ exports.getHostByName = function (domain, callback) { // Easy DNS A/AAAA look up exports.lookup = function (domain, callback) { - channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { - if (domains4 && domains4.length) { - callback(null, domains4[0], 4); - } else { - channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { - if (domains6 && domains6.length) { - callback(null, domains6[0], 6); - } else { - callback(err, []); - } - }); - } - }); + var addressType = dns.isIP(domain); + if (addressType) { + process.nextTick(function () { + callback(null, domain, addressType); + }); + } else { + sys.puts('AF_INET look up ' + domain); + channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { + sys.puts('AF_INET result ' + domain + ' ' + sys.inspect(domains4)); + if (domains4 && domains4.length) { + callback(null, domains4[0], 4); + } else { + sys.puts('AF_INET6 look up ' + domain); + channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { + sys.puts('AF_INET6 result ' + domain + ' ' + sys.inspect(domains6)); + if (domains6 && domains6.length) { + callback(null, domains6[0], 6); + } else { + callback(err, []); + } + }); + } + }); + } }; diff --git a/src/node_cares.cc b/src/node_cares.cc index cba62209cb3..82d2a64b939 100644 --- a/src/node_cares.cc +++ b/src/node_cares.cc @@ -13,6 +13,31 @@ namespace node { using namespace v8; +static Handle IsIP(const Arguments& args) { + HandleScope scope; + + if (!args[0]->IsString()) { + return scope.Close(Integer::New(4)); + } + + String::Utf8Value s(args[0]->ToString()); + + // avoiding buffer overflows in the following strcat + // 2001:0db8:85a3:08d3:1319:8a2e:0370:7334 + // 39 = max ipv6 address. + if (s.length() > INET6_ADDRSTRLEN) { + return scope.Close(Integer::New(0)); + } + + struct sockaddr_in6 a; + + if (inet_pton(AF_INET, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(4)); + if (inet_pton(AF_INET6, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(6)); + + return scope.Close(Integer::New(0)); +} + + class Channel : public ObjectWrap { public: static void Initialize(Handle target); @@ -104,6 +129,8 @@ void Cares::Initialize(Handle target) { target->Set(String::NewSymbol("EREFUSED"), Integer::New(ARES_EREFUSED)); target->Set(String::NewSymbol("SERVFAIL"), Integer::New(ARES_ESERVFAIL)); + NODE_SET_METHOD(target, "isIP", IsIP); + Channel::Initialize(target); } @@ -657,4 +684,6 @@ void Channel::SockStateCb(void *data, int sock, int read, int write) { } + + } // namespace node diff --git a/test/simple/test-c-ares.js b/test/simple/test-c-ares.js index 683babc4747..e24225e90e7 100644 --- a/test/simple/test-c-ares.js +++ b/test/simple/test-c-ares.js @@ -15,14 +15,24 @@ dns.getHostByName('127.0.0.1', function (error, result) { assert.deepEqual(['127.0.0.1'], result); }); -dns.lookup('127.0.0.1', function (error, result, ipVersion) { - assert.deepEqual('127.0.0.1', result); - assert.equal(4, ipVersion); +dns.lookup(null, function (error, result, addressType) { + assert.equal(null, result); + assert.equal(4, addressType); }); -dns.lookup('ipv6.google.com', function (error, result, ipVersion) { +dns.lookup('127.0.0.1', function (error, result, addressType) { + assert.equal('127.0.0.1', result); + assert.equal(4, addressType); +}); + +dns.lookup('::1', function (error, result, addressType) { + assert.equal('::1', result); + assert.equal(6, addressType); +}); + +dns.lookup('ipv6.google.com', function (error, result, addressType) { if (error) throw error; p(arguments); //assert.equal('string', typeof result); - assert.equal(6, ipVersion); + assert.equal(6, addressType); }); From 33e774eeba5a97af41fd17a8eb03b333a98ade33 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 16:05:07 -0700 Subject: [PATCH 32/73] Use c-ares in lib/net.js --- lib/net.js | 51 +++++---------------------------------------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/lib/net.js b/lib/net.js index c143f77ca10..7d769e920a7 100644 --- a/lib/net.js +++ b/lib/net.js @@ -1,6 +1,7 @@ var sys = require("sys"); var fs = require("fs"); var events = require("events"); +var dns = require('dns_cares'); var kMinPoolSpace = 128; var kPoolSize = 40*1024; @@ -38,8 +39,6 @@ var toRead = binding.toRead; var setNoDelay = binding.setNoDelay; var socketError = binding.socketError; var getsockname = binding.getsockname; -var getaddrinfo = binding.getaddrinfo; -var isIP = binding.isIP; var errnoException = binding.errnoException; var EINPROGRESS = binding.EINPROGRESS; var ENOENT = binding.ENOENT; @@ -615,11 +614,11 @@ Stream.prototype.connect = function () { // TODO dns resolution on arguments[1] var port = arguments[0]; self._resolving = true; - lookupDomainName(arguments[1], function (err, ip, isV4) { + dns.lookup(arguments[1], function (err, ip, addressType) { if (err) { self.emit('error', err); } else { - self.type = isV4 ? 'tcp4' : 'tcp6'; + self.type = addressType == 4 ? 'tcp4' : 'tcp6'; self.fd = socket(self.type); self._resolving = false; doConnect(self, port, ip); @@ -759,46 +758,6 @@ exports.createServer = function (listener) { return new Server(listener); }; -// This function does both an ipv4 and ipv6 look up. -// It first tries the ipv4 look up, if that fails, then it does the ipv6. -// callback(dn, isV4 -function lookupDomainName (dn, callback) { - var kind = isIP(dn); - if (kind) { - // Always wait until the next tick this is so people can do - // - // server.listen(8000); - // server.addListener('listening', fn); - // - // Marginally slower, but a lot fewer WTFs. - process.nextTick(function () { - callback(null, dn, kind == 4 ? true : false); - }); - } else { - debug("getaddrinfo 4 " + dn); - getaddrinfo(dn, 4, function (err, r4) { - if (err) { - callback(err); - } else if (r4.length > 0) { - debug("getaddrinfo 4 found " + r4); - callback(null, r4[0], true); - } else { - debug("getaddrinfo 6 " + dn); - getaddrinfo(dn, 6, function (err, r6) { - if (err) { - callback(err); - } else if (r6.length == 0) { - callback(new Error("No address associated with hostname " + dn)); - } else { - debug("getaddrinfo 6 found " + r6); - callback(null, r6[0], false); - } - }); - } - }); - } -} - // Listen on a UNIX socket // server.listen("/tmp/socket"); @@ -854,11 +813,11 @@ Server.prototype.listen = function () { } else { // the first argument is the port, the second an IP var port = arguments[0]; - lookupDomainName(arguments[1], function (err, ip, isV4) { + dns.lookup(arguments[1], function (err, ip, addressType) { if (err) { self.emit('error', err); } else { - self.type = isV4 ? 'tcp4' : 'tcp6'; + self.type = addressType == 4 ? 'tcp4' : 'tcp6'; self.fd = socket(self.type); bind(self.fd, port, ip); self._doListen(); From 970e9025fe17756f658bea97cc2c2969d71a7fa1 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 16:09:10 -0700 Subject: [PATCH 33/73] Remove debugging statements from dns_cares --- lib/dns_cares.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/dns_cares.js b/lib/dns_cares.js index 11caa3a067b..6794ef426f1 100644 --- a/lib/dns_cares.js +++ b/lib/dns_cares.js @@ -1,5 +1,4 @@ var dns = process.binding('cares'); -var sys = require('sys'); // TODO remove me var watchers = {}; @@ -101,15 +100,11 @@ exports.lookup = function (domain, callback) { callback(null, domain, addressType); }); } else { - sys.puts('AF_INET look up ' + domain); channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { - sys.puts('AF_INET result ' + domain + ' ' + sys.inspect(domains4)); if (domains4 && domains4.length) { callback(null, domains4[0], 4); } else { - sys.puts('AF_INET6 look up ' + domain); channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { - sys.puts('AF_INET6 result ' + domain + ' ' + sys.inspect(domains6)); if (domains6 && domains6.length) { callback(null, domains6[0], 6); } else { From 0281e1acf6e9cb3cd668dda91d4933160c4b95a7 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 16:19:50 -0700 Subject: [PATCH 34/73] Fix benchmark script for testing both old and new version --- benchmark/http_simple.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 99685f78ab2..9bfeadb2cc5 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -1,7 +1,10 @@ path = require("path"); var puts = require("sys").puts; -http = require("http"); +var old = false; + +http = require(old ? "http_old" : 'http'); +if (old) puts('old version'); fixed = "" for (var i = 0; i < 20*1024; i++) { @@ -49,5 +52,6 @@ http.createServer(function (req, res) { , "Content-Length": content_length } ); + if (old) res.write(body, 'ascii'); res.close(body, 'ascii'); }).listen(8000); From d923c94a0ca6ca4aa23318013de443dbb83398cb Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 7 Apr 2010 18:25:37 -0700 Subject: [PATCH 35/73] Remove udns --- LICENSE | 4 - deps/udns/.cvsignore | 14 - deps/udns/COPYING.LGPL | 504 -------------- deps/udns/Makefile.in | 198 ------ deps/udns/NEWS | 85 --- deps/udns/NOTES | 222 ------ deps/udns/TODO | 69 -- deps/udns/configure | 168 ----- deps/udns/configure.lib | 268 ------- deps/udns/debian/changelog | 136 ---- deps/udns/debian/control | 33 - deps/udns/debian/copyright | 23 - deps/udns/debian/rules | 93 --- deps/udns/dnsget.1 | 182 ----- deps/udns/dnsget.c | 726 ------------------- deps/udns/ex-rdns.c | 113 --- deps/udns/getopt.c | 165 ----- deps/udns/inet_XtoX.c | 327 --------- deps/udns/rblcheck.1 | 151 ---- deps/udns/rblcheck.c | 377 ---------- deps/udns/udns.3 | 1351 ------------------------------------ deps/udns/udns.h | 745 -------------------- deps/udns/udns_XtoX.c | 50 -- deps/udns/udns_bl.c | 160 ----- deps/udns/udns_dn.c | 382 ---------- deps/udns/udns_dntosp.c | 30 - deps/udns/udns_init.c | 231 ------ deps/udns/udns_misc.c | 67 -- deps/udns/udns_parse.c | 169 ----- deps/udns/udns_resolver.c | 1294 ---------------------------------- deps/udns/udns_rr_a.c | 123 ---- deps/udns/udns_rr_mx.c | 91 --- deps/udns/udns_rr_naptr.c | 128 ---- deps/udns/udns_rr_ptr.c | 109 --- deps/udns/udns_rr_srv.c | 154 ---- deps/udns/udns_rr_txt.c | 98 --- lib/dns.js | 148 +++- lib/dns_cares.js | 150 ---- lib/net.js | 2 +- src/node.cc | 11 - src/node_dns.cc | 514 -------------- src/node_dns.h | 16 - test/disabled/test-dns.js | 2 +- test/simple/test-c-ares.js | 2 +- wscript | 43 +- 45 files changed, 126 insertions(+), 9802 deletions(-) delete mode 100644 deps/udns/.cvsignore delete mode 100644 deps/udns/COPYING.LGPL delete mode 100644 deps/udns/Makefile.in delete mode 100644 deps/udns/NEWS delete mode 100644 deps/udns/NOTES delete mode 100644 deps/udns/TODO delete mode 100755 deps/udns/configure delete mode 100644 deps/udns/configure.lib delete mode 100644 deps/udns/debian/changelog delete mode 100644 deps/udns/debian/control delete mode 100644 deps/udns/debian/copyright delete mode 100755 deps/udns/debian/rules delete mode 100644 deps/udns/dnsget.1 delete mode 100644 deps/udns/dnsget.c delete mode 100644 deps/udns/ex-rdns.c delete mode 100644 deps/udns/getopt.c delete mode 100644 deps/udns/inet_XtoX.c delete mode 100644 deps/udns/rblcheck.1 delete mode 100644 deps/udns/rblcheck.c delete mode 100644 deps/udns/udns.3 delete mode 100644 deps/udns/udns.h delete mode 100644 deps/udns/udns_XtoX.c delete mode 100644 deps/udns/udns_bl.c delete mode 100644 deps/udns/udns_dn.c delete mode 100644 deps/udns/udns_dntosp.c delete mode 100644 deps/udns/udns_init.c delete mode 100644 deps/udns/udns_misc.c delete mode 100644 deps/udns/udns_parse.c delete mode 100644 deps/udns/udns_resolver.c delete mode 100644 deps/udns/udns_rr_a.c delete mode 100644 deps/udns/udns_rr_mx.c delete mode 100644 deps/udns/udns_rr_naptr.c delete mode 100644 deps/udns/udns_rr_ptr.c delete mode 100644 deps/udns/udns_rr_srv.c delete mode 100644 deps/udns/udns_rr_txt.c delete mode 100644 lib/dns_cares.js delete mode 100644 src/node_dns.cc delete mode 100644 src/node_dns.h diff --git a/LICENSE b/LICENSE index 7a3e96b90e2..532a7d1b692 100644 --- a/LICENSE +++ b/LICENSE @@ -15,10 +15,6 @@ are: - The SCONS build system, located at tools/scons. Copyrighted by the SCONS Foundation. Released under an MIT license. - - UDNS, an asynchronous DNS client, located at deps/udns. Copyrighted by - Michael Tokarev . Released under the GNU Lesser General - Public License version 2.1. - - C-Ares, an asynchronous DNS client, located at deps/c-ares. Copyright by the Massachusetts Institute of Technology; authored by Greg Hudson, Daniel Stenberg and others. Released under an MIT license. diff --git a/deps/udns/.cvsignore b/deps/udns/.cvsignore deleted file mode 100644 index 81946db555c..00000000000 --- a/deps/udns/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -udns*.tar.gz -udns_codes.c -udns.3.html -*.lo -*_s -libudns.so.* -dnsget -ex-rdns -rblcheck -Makefile -config.h -config.status -config.log -build-stamp diff --git a/deps/udns/COPYING.LGPL b/deps/udns/COPYING.LGPL deleted file mode 100644 index b1e3f5a2638..00000000000 --- a/deps/udns/COPYING.LGPL +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/deps/udns/Makefile.in b/deps/udns/Makefile.in deleted file mode 100644 index 4e0e56ec593..00000000000 --- a/deps/udns/Makefile.in +++ /dev/null @@ -1,198 +0,0 @@ -#! /usr/bin/make -rf -# $Id: Makefile.in,v 1.11 2007/01/15 21:19:08 mjt Exp $ -# libudns Makefile -# -# Copyright (C) 2005 Michael Tokarev -# This file is part of UDNS library, an async DNS stub resolver. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library, in file named COPYING.LGPL; if not, -# write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA - -NAME = udns -VERS = 0.0.9 -SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_init.c \ - udns_misc.c udns_XtoX.c \ - udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \ - udns_rr_srv.c udns_rr_naptr.c udns_codes.c -USRCS = dnsget.c rblcheck.c ex-rdns.c -DEB = debian/copyright debian/changelog debian/control debian/rules -DIST = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \ - NEWS TODO NOTES Makefile.in configure configure.lib \ - inet_XtoX.c getopt.c - -OBJS = $(SRCS:.c=.o) $(GEN:.c=.o) -LIB = lib$(NAME).a -LIBFL = -L. -l$(NAME) - -SOVER = 0 -SOBJS = $(OBJS:.o=.lo) -SOLIB = lib$(NAME)_s.so -SOLIBV = lib$(NAME).so.$(SOVER) -SOLIBFL= -L. -l$(NAME)_s - -LIBS = $(LIB) $(SOLIBV) - -UTILS = $(USRCS:.c=) -UOBJS = $(USRCS:.c=.o) -SOUTILS = $(USRCS:.c=_s) - -NAMEPFX = $(NAME)-$(VERS) - -CC = @CC@ -RANLIB = @RANLIB@ -CFLAGS = @CFLAGS@ -CDEFS = @CDEFS@ -PICFLAGS = -fPIC -AWK = awk - -all: staticlib - -.SUFFIXES: .c .o .lo - -static: $(LIB) $(UTILS) -staticlib: $(LIB) -$(LIB): $(OBJS) - -rm -f $@ - $(AR) rv $@ $(OBJS) - $(RANLIB) $(LIB) -.c.o: - $(CC) $(CFLAGS) $(CDEFS) -c $< - -shared: $(SOLIBV) $(SOUTILS) -sharedlib: $(SOLIBV) - -$(SOLIBV): $(SOBJS) - $(CC) -shared -Wl,--soname,$(SOLIBV) -o $@ $(SOBJS) -$(SOLIB): $(SOLIBV) - rm -f $@ - ln -s $(SOLIBV) $@ -.c.lo: - $(CC) $(CFLAGS) $(PICFLAGS) $(CDEFS) -o $@ -c $< - -# udns_codes.c is generated from udns.h -udns_codes.c: udns.h - @echo Generating $@ - @set -e; exec >$@.tmp; \ - set T type C class R rcode; \ - echo "/* Automatically generated. */"; \ - echo "#include \"udns.h\""; \ - while [ "$$1" ]; do \ - echo; \ - echo "const struct dns_nameval dns_$${2}tab[] = {"; \ - $(AWK) "/^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \ - { printf \" {%s,\\\"%s\\\"},\\n\", \$$1, substr(\$$1,7) }" \ - udns.h ; \ - echo " {0,0}};"; \ - echo "const char *dns_$${2}name(enum dns_$${2} code) {"; \ - echo " static char nm[20];"; \ - echo " switch(code) {"; \ - $(AWK) "BEGIN{i=0} \ - /^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \ - {printf \" case %s: return dns_$${2}tab[%d].name;\\n\",\$$1,i++}\ - " udns.h ; \ - echo " }"; \ - echo " return _dns_format_code(nm,\"$$2\",code);"; \ - echo "}"; \ - shift 2; \ - done - @mv $@.tmp $@ - -udns.3.html: udns.3 - groff -man -Thtml udns.3 > $@.tmp - mv $@.tmp $@ - -dist: $(NAMEPFX).tar.gz -$(NAMEPFX).tar.gz: $(DIST) $(DEB) - mkdir $(NAMEPFX) $(NAMEPFX)/debian - ln $(DIST) $(NAMEPFX) - ln $(DEB) $(NAMEPFX)/debian - tar cvfz $@ $(NAMEPFX) - rm -rf $(NAMEPFX) -subdist: - cp -p $(DIST) $(TARGET)/ - -clean: - rm -f $(OBJS) - rm -f $(SOBJS) - rm -f $(UOBJS) - rm -f build-stamp config.log -distclean: clean - rm -f $(LIBS) $(SOLIB) udns.3.html - rm -f $(UTILS) $(SOUTILS) - rm -f config.status config.h Makefile - - -Makefile: configure configure.lib Makefile.in - ./configure - @echo - @echo Please rerun make >&2 - @exit 1 - -.PHONY: all static staticlib shared sharedlib dist clean distclean subdist \ - depend dep deps - -depend dep deps: $(SRCS) $(USRC) - @echo Generating deps for: - @echo \ $(SRCS) - @echo \ $(USRCS) - @sed '/^# depend/q' Makefile.in > Makefile.tmp - @set -e; \ - for f in $(SRCS) $(USRCS); do \ - echo $${f%.c}.o $${f%.c}.lo: $$f \ - `sed -n 's/^#[ ]*include[ ]*"\(.*\)".*/\1/p' $$f`; \ - done >> Makefile.tmp; \ - for f in $(USRCS:.c=.o); do \ - echo "$${f%.?}: $$f \$$(LIB)"; \ - echo " \$$(CC) \$$(CFLAGS) -o \$$@ $$f \$$(LIBFL)"; \ - echo "$${f%.?}_s: $$f \$$(SOLIB)"; \ - echo " \$$(CC) \$$(CFLAGS) -o \$$@ $$f \$$(SOLIBFL)"; \ - done >> Makefile.tmp ; \ - if cmp Makefile.tmp Makefile.in >/dev/null 2>&1 ; then \ - echo Makefile.in unchanged; rm -f Makefile.tmp; \ - else \ - echo Updating Makfile.in; mv -f Makefile.tmp Makefile.in ; \ - fi - -# depend -udns_dn.o udns_dn.lo: udns_dn.c udns.h -udns_dntosp.o udns_dntosp.lo: udns_dntosp.c udns.h -udns_parse.o udns_parse.lo: udns_parse.c udns.h -udns_resolver.o udns_resolver.lo: udns_resolver.c config.h udns.h -udns_init.o udns_init.lo: udns_init.c config.h udns.h -udns_misc.o udns_misc.lo: udns_misc.c udns.h -udns_XtoX.o udns_XtoX.lo: udns_XtoX.c config.h udns.h inet_XtoX.c -udns_rr_a.o udns_rr_a.lo: udns_rr_a.c udns.h -udns_rr_ptr.o udns_rr_ptr.lo: udns_rr_ptr.c udns.h -udns_rr_mx.o udns_rr_mx.lo: udns_rr_mx.c udns.h -udns_rr_txt.o udns_rr_txt.lo: udns_rr_txt.c udns.h -udns_bl.o udns_bl.lo: udns_bl.c udns.h -udns_rr_srv.o udns_rr_srv.lo: udns_rr_srv.c udns.h -udns_rr_naptr.o udns_rr_naptr.lo: udns_rr_naptr.c udns.h -udns_codes.o udns_codes.lo: udns_codes.c udns.h -dnsget.o dnsget.lo: dnsget.c config.h udns.h getopt.c -rblcheck.o rblcheck.lo: rblcheck.c udns.h getopt.c -ex-rdns.o ex-rdns.lo: ex-rdns.c udns.h -dnsget: dnsget.o $(LIB) - $(CC) $(CFLAGS) -o $@ dnsget.o $(LIBFL) -dnsget_s: dnsget.o $(SOLIB) - $(CC) $(CFLAGS) -o $@ dnsget.o $(SOLIBFL) -rblcheck: rblcheck.o $(LIB) - $(CC) $(CFLAGS) -o $@ rblcheck.o $(LIBFL) -rblcheck_s: rblcheck.o $(SOLIB) - $(CC) $(CFLAGS) -o $@ rblcheck.o $(SOLIBFL) -ex-rdns: ex-rdns.o $(LIB) - $(CC) $(CFLAGS) -o $@ ex-rdns.o $(LIBFL) -ex-rdns_s: ex-rdns.o $(SOLIB) - $(CC) $(CFLAGS) -o $@ ex-rdns.o $(SOLIBFL) diff --git a/deps/udns/NEWS b/deps/udns/NEWS deleted file mode 100644 index 3234a6b5ea9..00000000000 --- a/deps/udns/NEWS +++ /dev/null @@ -1,85 +0,0 @@ -$Id: NEWS,v 1.11 2007/01/15 21:19:08 mjt Exp $ - -User-visible changes in udns library. Recent changes on top. - -0.0.9 (16 Jan 2007) - - - incompat: minor API changes in dns_init() &friends. dns_init() - now requires extra `struct dns_ctx *' argument. Not bumped - soversion yet - I only expect one "release" with this change, - 0.1 will have more changes and will increment so version - - - many small bugfixes, here and there - - - more robust FORMERR replies handling - not only such replies are now - recognized, but udns retries queries without EDNS0 extensions if tried - with, but server reported FORMERR - - - portability changes, udns now includes getopt() implementation fo - the systems lacking it (mostly windows), and dns_ntop()&dns_pton(), - which are either just wrappers for system functions or reimplementations. - - - build is now based on autoconf-like configuration - - - NAPTR (RFC3403) RR decoding support - - - new file NOTES which complements TODO somewhat, and includes some - important shortcomings - - - many internal cleanups, including some preparations for better error - recovery, security and robustness (and thus API changes) - - - removed some #defines which are now unused (like DNS_MAXSRCH) - - - changed WIN32 to WINDOWS everywhere in preprocessor tests, - to be able to build it on win64 as well - -0.0.8 (12 Sep 2005) - - - added SRV records (rfc2782) parsing, - thanks to Thadeu Lima de Souza Cascardo for implementation. - - - bugfixes: - o use uninitialized value when no reply, library died with assertion: - assert((status < 0 && result == 0) || (status >= 0 && result != 0)). - o on some OSes, struct sockaddr_in has additional fields, so - memcmp'ing two sockaddresses does not work. - - - rblcheck(.1) - -0.0.7 (20 Apr 2005) - - - dnsget.1 manpage and several enhancements to dnsget. - - - allow nameserver names for -n option of dnsget. - - - API change: all dns_submit*() routines now does not expect - last `now' argument, since requests aren't sent immediately - anymore. - - - API change: different application timer callback mechanism. - Udns now uses single per-context timer instead of per-query. - - - don't assume DNS replies only contain backward DN pointers, - allow forward pointers too. Change parsing API. - - - debianize - -0.0.6 (08 Apr 2005) - - - use double sorted list for requests (sorted by deadline). - This should significantly speed up timeout processing for - large number of requests. - - - changed debugging interface, so it is finally useable - (still not documented). - - - dnsget routine is now Officially Useable, and sometimes - even more useable than `host' from BIND distribution - (and sometimes not - dnsget does not have -C option - and TCP mode) - - - Debian packaging in debian/ -- udns is now maintained as a - native Debian package. - - - alot (and I really mean alot) of code cleanups all over. diff --git a/deps/udns/NOTES b/deps/udns/NOTES deleted file mode 100644 index 6c246824af5..00000000000 --- a/deps/udns/NOTES +++ /dev/null @@ -1,222 +0,0 @@ -Assorted notes about udns (library). - -UDP-only mode -~~~~~~~~~~~~~ - -First of all, since udns is (currently) UDP-only, there are some -shortcomings. - -It assumes that a reply will fit into a UDP buffer. With adoption of EDNS0, -and general robustness of IP stacks, in most cases it's not an issue. But -in some cases there may be problems: - - - if an RRset is "very large" so it does not fit even in buffer of size - requested by the library (current default is 4096; some servers limits - it further), we will not see the reply, or will only see "damaged" - reply (depending on the server). - - - many DNS servers ignores EDNS0 option requests. In this case, no matter - which buffer size udns library will request, such servers reply is limited - to 512 bytes (standard pre-EDNS0 DNS packet size). (Udns falls back to - non-EDNO0 query if EDNS0-enabled one received FORMERR or NOTIMPL error). - -The problem is that with this, udns currently will not consider replies with -TC (truncation) bit set, and will treat such replies the same way as it -treats SERVFAIL replies, thus trying next server, or temp-failing the query -if no more servers to try. In other words, if the reply is really large, or -if the servers you're using don't support EDNS0, your application will be -unable to resolve a given name. - -Yet it's not common situation - in practice, it's very rare. - -Implementing TCP mode isn't difficult, but it complicates API significantly. -Currently udns uses only single UDP socket (or - maybe in the future - two, -see below), but in case of TCP, it will need to open and close sockets for -TCP connections left and right, and that have to be integrated into an -application's event loop in an easy and efficient way. Plus all the -timeouts - different for connect(), write, and several stages of read. - -IPv6 vs IPv4 usage -~~~~~~~~~~~~~~~~~~ - -This is only relevant for nameservers reachable over IPv6, NOT for IPv6 -queries. I.e., if you've IPv6 addresses in 'nameservers' line in your -/etc/resolv.conf file. Even more: if you have BOTH IPv6 AND IPv4 addresses -there. Or pass them to udns initialization routines. - -Since udns uses a single UDP socket to communicate with all nameservers, -it should support both v4 and v6 communications. Most current platforms -supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e, -"tunnelling" IPv4 inside IPv6. But not all systems supports this. And -more, it has been said that such mode is deprecated. - -So, list only IPv4 or only IPv6 addresses, but don't mix them, in your -/etc/resolv.conf. - -An alternative is to use two sockets instead of 1 - one for IPv6 and one -for IPv4. For now I'm not sure if it's worth the complexity - again, of -the API, not the library itself (but this will not simplify library either). - -Single socket for all queries -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using single UDP socket for sending queries to all nameservers has obvious -advantages. First it's, again, trivial, simple to use API. And simple -library too. Also, after sending queries to all nameservers (in case first -didn't reply in time), we will be able to receive late reply from first -nameserver and accept it. - -But this mode has disadvantages too. Most important is that it's much easier -to send fake reply to us, as the UDP port where we expects the reply to come -to is constant during the whole lifetime of an application. More secure -implementations uses random port for every single query. While port number -(16 bits integer) can not hold much randomness, it's still of some help. -Ok, udns is a stub resolver, so it expects sorta friendly environment, but -on LAN it's usually much easier to fire an attack, due to the speed of local -network, where a bad guy can generate alot of packets in a short time. - -Choosing of DNS QueryID -~~~~~~~~~~~~~~~~~~~~~~~ - -Currently, udns uses sequential number for query IDs. Which simplifies -attacks even more (c.f. the previous item about single UDP port), making -them nearly trivial. The library should use random number for query ID. -But there's no portable way to get random numbers, even on various flavors -of Unix. It's possible to use low bits from tv_nsec field returned by -gettimeofday() (current time, nanoseconds), but I wrote the library in -a way to avoid making system calls where possible, because many syscalls -means many context switches and slow processes as a result. Maybe use some -application-supplied callback to get random values will be a better way, -defaulting to gettimeofday() method. - -Note that a single query - even if (re)sent to different nameservers, several -times (due to no reply received in time), uses the same qID assigned when it -was first dispatched. So we have: single UDP socket (fixed port number), -sequential (= trivially predictable) qIDs, and long lifetime of those qIDs. -This all makes (local) attacks against the library really trivial. - -See also comments in udns_resolver.c, udns_newid(). - -And note that at least some other stub resolvers out there (like c-ares -for example) also uses sequential qID. - -Assumptions about RRs returned -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Currently udns processes records in the reply it received sequentially. -This means that order of the records is significant. For example, if -we asked for foo.bar A, but the server returned that foo.bar is a CNAME -(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when -the CNAME should come first in reply, followed by A. While DNS specs -does not say anything about order of records - it's an rrSET - unordered, - -I think an implementation which returns the records in "wrong" order is -somewhat insane... - -CNAME recursion -~~~~~~~~~~~~~~~ - -Another interesting point is the handling of CNAMEs returned as replies -to non-CNAME queries. If we asked for foo.bar A, but it's a CNAME, udns -expects BOTH the CNAME itself and the target DN to be present in the reply. -In other words, udns DOES NOT RECURSE CNAMES. If we asked for foo.bar A, -but only record in reply was that foo.bar is a CNAME for bar.baz, udns will -return no records to an application (NXDOMAIN). Strictly speaking, udns -should repeat the query asking for bar.baz A, and recurse. But since it's -stub resolver, recursive resolver should recurse for us instead. - -It's not very difficult to implement, however. Probably with some (global?) -flag to en/dis-able the feature. Provided there's some demand for it. - -To clarify: udns handles CNAME recursion in a single reply packet just fine. - -Note also that standard gethostbyname() routine does not recurse in this -situation, too. - -Error reporting -~~~~~~~~~~~~~~~ - -Too many places in the code (various failure paths) sets generic "TEMPFAIL" -error condition. For example, if no nameserver replied to our query, an -application will get generic TEMPFAIL, instead of something like TIMEDOUT. -This probably should be fixed, but most applications don't care about the -exact reasons of failure - 4 common cases are already too much: - - query returned some valid data - - NXDOMAIN - - valid domain but no data of requested type - =NXDOMAIN in most cases - - temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN - by (naive) applications. -DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important -case! And adding more variations for the temp error case is complicating things -even more - again, from an application writer standpoint. For diagnostics, -such more specific error cases are of good help. - -Planned API changes -~~~~~~~~~~~~~~~~~~~ - -At least one thing I want to change for 0.1 version is a way how queries are -submitted and how replies are handled. - -I want to made dns_query object to be owned by an application. So that instead -of udns library allocating it for the lifetime of query, it will be pre- -allocated by an application. This simplifies and enhances query submitting -interface, and complicates it a bit too, in simplest cases. - -Currently, we have: - -dns_submit_dn(dn, cls, typ, flags, parse, cbck, data) -dns_submit_p(name, cls, typ, flags, parse, cbck, data) -dns_submit_a4(ctx, name, flags, cbck, data) - -and so on -- with many parameters missed for type-specific cases, but generic -cases being too complex for most common usage. - -Instead, with dns_query being owned by an app, we will be able to separately -set up various parts of the query - domain name (various forms), type&class, -parser, flags, callback... and even change them at runtime. And we will also -be able to reuse query structures, instead of allocating/freeing them every -time. So the whole thing will look something like: - - q = dns_alloc_query(); - dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data); - -The idea is to have a set of functions accepting struct dns_query* and -returning it (so the calls can be "nested" like the above), to set up -relevant parts of the query - specific type of callback, conversion from -(type-specific) query parameters into a domain name (this is for type- -specific query initializers), and setting various flags and options and -type&class things. - -One example where this is almost essential - if we want to support -per-query set of nameservers (which isn't at all useless: imagine a -high-volume mail server, were we want to direct DNSBL queries to a separate -set of nameservers, and rDNS queries to their own set and so on). Adding -another argument (set of nameservers to use) to EVERY query submitting -routine is.. insane. Especially since in 99% cases it will be set to -default NULL. But with such "nesting" of query initializers, it becomes -trivial. - -Another way to do the same is to manipulate query object right after a -query has been submitted, but before any events processing (during this -time, query object is allocated and initialized, but no actual network -packets were sent - it will happen on the next event processing). But -this way it become impossible to perform syncronous resolver calls, since -those calls hide query objects they use internally. - -Speaking of replies handling - the planned change is to stop using dynamic -memory (malloc) inside the library. That is, instead of allocating a buffer -for a reply dynamically in a parsing routine (or memdup'ing the raw reply -packet if no parsing routine is specified), I want udns to return the packet -buffer it uses internally, and change parsing routines to expect a buffer -for result. When parsing, a routine will return true amount of memory it -will need to place the result, regardless of whenever it has enough room -or not, so that an application can (re)allocate properly sized buffer and -call a parsing routine again. - -Another modification I plan to include is to have an ability to work in -terms of domain names (DNs) as used with on-wire DNS packets, not only -with asciiz representations of them. For this to work, the above two -changes (query submission and result passing) have to be completed first -(esp. the query submission part), so that it will be possible to specify -some additional query flags (for example) to request domain names instead -of the text strings, and to allow easy query submissions with either DNs -or text strings. diff --git a/deps/udns/TODO b/deps/udns/TODO deleted file mode 100644 index 41299bcd969..00000000000 --- a/deps/udns/TODO +++ /dev/null @@ -1,69 +0,0 @@ -$Id: TODO,v 1.13 2007/01/15 21:19:08 mjt Exp $ - -The following is mostly an internal, not user-visible stuff. - -* rearrange an API to make dns_query object owned by application, - so that it'll look like this: - struct dns_query *q; - q = udns_query_alloc(ctx); - udns_query_set(q, options, domain_name, flags, ...); - udns_query_submit(ctx, q); - or - udns_query_resolve(ctx, q); - -* allow NULL callbacks? Or provide separate resolver - context list of queries which are done but wich did not - have callback, and dns_pick() routine to retrieve results - from this query, i.e. allow non-callback usage? The - non-callback usage may be handy sometimes (any *good* - example?), but it will be difficult to provide type-safe - non-callback interface due to various RR-specific types - in use. - -* DNS_OPT_FLAGS should be DNS_OPT_ADDFLAGS and DNS_OPT_SETFLAGS. - Currently one can't add a single flag bit but preserve - existing bits... at least not without retrieving all current - flags before, which isn't that bad anyway. - -* dns_set_opts() may process flags too (such as aaonly etc) - -* a way to disable $NSCACHEIP et al processing? - (with now separate dns_init() and dns_reset(), it has finer - control, but still no way to init from system files but ignore - environment variables and the like) - -* initialize/open the context automatically, and be more - liberal about initialization in general? - -* dns_init(ctx, do_open) - make the parameter opposite, aka - dns_init(ctx, skip_open) ? - -* allow TCP queue? - -* And oh, qID should really be random. Or... not. - See notes in udns_resolver.c, dns_newid(). - -* more accurate error reporting. Currently, udns always returns TEMPFAIL, - but don't specify why it happened (ENOMEM, timeout, etc). - -* check the error value returned by recvfrom() and - sendto() and determine which errors to ignore. - -* maybe merge dns_timeouts() and dns_ioevent(), to have - only one entry point for everything? For traditional - select-loop-based eventloop it may be easier, but for - callback-driven event loops the two should be separate. - Provide an option, or a single dns_events() entry point - for select-loop approach, or just call dns_ioevent() - from within dns_timeouts() (probably after renaming - it to be dns_events()) ? - -* implement /etc/hosts lookup too, ala [c-]ares?? - -* sortlist support? - -* windows port? Oh no please!.. At least, I can't do it myself - because of the lack of platform. - Ok ok, the Windows port is in progress. Christian Prahauser - from cosy.sbg.ac.at is helping with that. - Other folks done some more work in this area. diff --git a/deps/udns/configure b/deps/udns/configure deleted file mode 100755 index 14e1b7078c4..00000000000 --- a/deps/udns/configure +++ /dev/null @@ -1,168 +0,0 @@ -#! /bin/sh -# $Id: configure,v 1.4 2007/01/07 23:19:40 mjt Exp $ -# autoconf-style configuration script -# - -set -e - -name=udns - -if [ -f udns.h -a -f udns_resolver.c ] ; then : -else - echo "configure: error: sources not found at `pwd`" >&2 - exit 1 -fi - -options="ipv6" - -for opt in $options; do - eval enable_$opt= -done - -if [ -f config.status ]; then - . ./config.status -fi - -enable() { - opt=`echo "$1" | sed 's/^--[^-]*-//'` - case "$opt" in - ipv6|stats|master_dump|zlib|dso) ;; - master-dump) opt=master_dump ;; - *) echo "configure: unrecognized option \`$1'" >&2; exit 1;; - esac - eval enable_$opt=$2 -} - -while [ $# -gt 0 ]; do - case "$1" in - --disable-*|--without-*|--no-*) enable "$1" n;; - --enable-*|--with-*) enable "$1" y;; - --help | --hel | --he | --h | -help | -hel | -he | -h ) - cat <&2; exit 1 ;; - esac - shift -done - -. ./configure.lib - -ac_msg "configure" -ac_result "$name package" - -ac_prog_c_compiler_v -ac_prog_ranlib_v - -ac_ign ac_yesno "for getopt()" ac_have GETOPT ac_link < -extern int optind; -extern char *optarg; -extern int getopt(int, char **, char *); -int main(int argc, char **argv) { - getopt(argc, argv, "abc"); - return optarg ? optind : 0; -} -EOF - -ac_ign \ - ac_yesno "for inet_pton() && inet_ntop()" \ - ac_have INET_PTON_NTOP \ - ac_link < -#include -#include -#include -int main() { - char buf[64]; - long x = 0; - inet_pton(AF_INET, &x, buf); - return inet_ntop(AF_INET, &x, buf, sizeof(buf)); -} -EOF - -if ac_yesno "for socklen_t" ac_compile < -#include -int foo() { socklen_t len; len = 0; return len; } -EOF -then : -else - ac_define socklen_t int -fi - -if ac_library_find_v 'socket and connect' "" "-lsocket -lnsl" < -#include -#include -int main() { - struct sockaddr_in6 sa; - sa.sin6_family = AF_INET6; - return 0; -} -EOF -then : -elif [ "$enable_ipv6" ]; then - ac_fatal "IPv6 is requested but not available" -fi -fi # !disable_ipv6? - -if ac_yesno "for poll()" ac_have POLL ac_link < -#include -int main() { - struct pollfd pfd[2]; - return poll(pfd, 2, 10); -} -EOF -then : -else - ac_ign ac_yesno "for sys/select.h" ac_have SYS_SELECT_H ac_cpp < -#include -EOF -fi - -ac_config_h -ac_output Makefile -ac_msg "creating config.status" -rm -f config.status -{ -echo "# automatically generated by configure to hold command-line options" -echo -found= -for opt in $options; do - eval val=\$enable_$opt - if [ -n "$val" ]; then - echo enable_$opt=$val - found=y - fi -done -if [ ! "$found" ]; then - echo "# (no options encountered)" -fi -} > config.status -ac_result ok - -ac_result "all done." -exit 0 diff --git a/deps/udns/configure.lib b/deps/udns/configure.lib deleted file mode 100644 index 541177a095b..00000000000 --- a/deps/udns/configure.lib +++ /dev/null @@ -1,268 +0,0 @@ -# configure.lib -# a library of shell routines for simple autoconf system -# - -set -e -ac_substitutes= -rm -f conftest* config.log -exec 5>config.log -cat <&5 -This file contains any messages produced by compilers etc while -running configure, to aid debugging if configure script makes a mistake. - -EOF - -case `echo "a\c"` in - *c*) ac_en=-n ac_ec= ;; - *) ac_en= ac_ec='\c' ;; -esac - -##### Messages -ac_msg() { - echo $ac_en "$*... $ac_ec" - echo ">>> $*" >&5 -} -ac_checking() { - echo $ac_en "checking $*... $ac_ec" - echo ">>> checking $*" >&5 -} -ac_result() { - echo "$1" - echo "=== $1" >&5 -} -ac_fatal() { - echo "configure: fatal: $*" >&2 - echo "=== FATAL: $*" >&5 - exit 1 -} -ac_warning() { - echo "configure: warning: $*" >&2 - echo "=== WARNING: $*" >&5 -} -ac_ign() { - "$@" || : -} - -# ac_run command... -# captures output in conftest.out -ac_run() { - # apparently UnixWare (for one) /bin/sh optimizes the following "if" - # "away", by checking if there's such a command BEFORE redirecting - # output. So error message (like "gcc: command not found") goes - # to stderr instead of to conftest.out, and `cat conftest.out' below - # fails. - if "$@" >conftest.out 2>&1; then - return 0 - else - echo "==== Command invocation failed. Command line was:" >&5 - echo "$*" >&5 - echo "==== compiler input was:" >&5 - cat conftest.c >&5 - echo "==== output was:" >&5 - cat conftest.out >&5 - echo "====" >&5 - return 1 - fi -} - -# common case for ac_verbose: yes/no result -ac_yesno() { - ac_checking "$1" - shift - if "$@"; then - ac_result yes - return 0 - else - ac_result no - return 1 - fi -} - -ac_subst() { - ac_substitutes="$ac_substitutes $*" -} - -ac_define() { - CDEFS="$CDEFS -D$1=${2:-1}" -} - -ac_have() { - ac_what=$1; shift - if "$@"; then - ac_define HAVE_$ac_what - eval ac_have_$ac_what=yes - return 0 - else - eval ac_have_$ac_what=no - return 1 - fi -} - -##### Compiling, linking - -# run a compiler -ac_run_compiler() { - rm -f conftest*; cat >conftest.c - ac_run $CC $CFLAGS $CDEFS "$@" conftest.c -} - -ac_compile() { - ac_run_compiler -c -} - -ac_link() { - ac_run_compiler -o conftest $LIBS "$@" -} - -ac_cpp() { - ac_run_compiler -E "$@" -} - -### check for C compiler. Set $CC, $CFLAGS etc -ac_prog_c_compiler_v() { - ac_checking "for C compiler" - rm -f conftest* - echo 'int main(int argc, char **argv) { return 0; }' >conftest.c - - if [ -n "$CC" ]; then - if ac_run $CC -o conftest conftest.c && ac_run ./conftest; then - ac_result "\$CC ($CC)" - else - ac_result no - ac_fatal "\$CC ($CC) is not a working compiler" - fi - else - for cc in gcc cc ; do - if ac_run $cc -o conftest conftest.c && ac_run ./conftest; then - ac_result "$cc" - CC=$cc - break - fi - done - if [ -z "$CC" ]; then - ac_result no - ac_fatal "no working C compiler found in \$PATH. please set \$CC variable" - fi - fi - if [ -z "$CFLAGS" ]; then - if ac_yesno "whenever C compiler ($CC) is GNU CC" \ - ac_grep_cpp yEs_mAsTeR <conftest.c - for lib in "$@"; do - if ac_run $CC $CFLAGS $LDFLAGS conftest.c -o conftest $LIBS $lib; then - found=y - break - fi - done - if [ ! "$found" ]; then - ac_result "not found" - return 1 - fi - if [ -z "$lib" ]; then - ac_result "ok (none needed)" - else - ac_result "ok ($lib)" - LIBS="$LIBS $lib" - fi -} - -ac_compile_run() { - ac_link "$@" && ac_run ./conftest -} - -ac_grep_cpp() { - pattern="$1"; shift - ac_cpp "$@" && grep "$pattern" conftest.out >/dev/null -} - -ac_output() { - for var in $ac_substitutes; do - eval echo "\"s|@$var@|\$$var|\"" - done >conftest.sed - for file in "$@"; do - ac_msg "creating $file" - if [ -f $file.in ]; then - sed -f conftest.sed $file.in > $file.tmp - mv -f $file.tmp $file - ac_result ok - else - ac_result failed - ac_fatal "$file.in not found" - fi - done - rm -f conftest* -} - -ac_config_h() { - h=${1:-config.h} - ac_msg "creating $h" - rm -f $1.tmp - echo "/* automatically generated by configure. */" > $h.tmp - echo "$CDEFS" | tr ' ' ' -' | sed -e 's/^-D/#define /' -e 's/=/ /' >> $h.tmp - if [ -f $h ] && cmp -s $h.tmp $h ; then - rm -f $h.tmp - ac_result unchanged - else - mv -f $h.tmp $h - ac_result ok - fi - CDEFS=-DHAVE_CONFIG_H -} diff --git a/deps/udns/debian/changelog b/deps/udns/debian/changelog deleted file mode 100644 index bd39c33d951..00000000000 --- a/deps/udns/debian/changelog +++ /dev/null @@ -1,136 +0,0 @@ -udns (0.0.9) unstable; urgency=low - - * s/EOVERFLOW/ENFILE, partly to make win32 happy - - * several win32 fixes - - * don't use `class' in udns.h, to make C++ happy - (thanks Markus Koetter for pointing this out) - - * fixed CNAME handling in dnsget tool. Another Thank You! goes - to Markus Koetter. - - * NAPTR (RFC3403) support, thanks to Mikael Magnusson - for this. - - * more Win32 fixes from Mikael Magnusson. I have to admit - I never tried to compile it on Win32. - - * added NOTES file - - * reworked initialisation stuff. Minor API changes -- new dns_reset(), - dns_init() now has one more argument, corrections to dns_close(), - dns_open(), dns_free(). Cleaned up *_internal() routines. - - * moved dns_init() routine into separate file. - - * reworked dn suffix searching. As a result, query only has - dnsq_dn[] field -- no header and EDNS0 "suffix", and query - packet is now formatted in dns_send() - - * added inet_XtoX.c - public domain implementations of inet_pton() - and inet_ntop(), inet_aton() and inet_ntoa() routines. - - * added getopt.c - public domain implementation of getopt() routine. - - * switched to autoconf-style configuration - - * introduce dns_random16() to generate query IDs - (currently based on gettimeofday.tv_usec) - - * dnsget: fix printing of -t ANY and -c any records, - thanks to Jaroslaw Rafa - - * implement dns_ntop() and dns_pton() as either wrappers or - reimplementations (using inet_XtoX.c) of inet_ntop() and inet_pton(). - Too much troubles with portability - it was a complete mess, each - OS has its own problems with them. - And use those routines everywhere. - - * s/WIN32/WINDOWS/g to allow building on WIN64. Oh well. - - * try to find query by ID first, don't drop header-only replies early. - This is in order to support FORMERR replies from nameservers which - don't understand EDNS0. - - * retry queries w/o EDNS0 if sent with it and if - server reported FORMERR or NOTIMPL - - * fixed debian/copyright and debian/control - - * rblcheck revamp - - -- Michael Tokarev Tue, 16 Jan 2007 00:00:28 +0300 - -udns (0.0.8) unstable; urgency=low - - * don't compare sockaddr_in's, but individual parts only - (on some OSes, there are additional fields in this structure - so memcmp() does not quite work) - - * use dnsc_t instead of unsigned char for DNs everywhere - - * SRV records (rfc2782) parsing, thanks to - Thadeu Lima de Souza Cascardo. - - * manpage fixes - - -- Michael Tokarev Mon, 12 Sep 2005 16:06:45 +0400 - -udns (0.0.7) unstable; urgency=low - - * added dnsget.1 and rblcheck.1 manpages. - - * internal: use generic list implementation in udns_resolver.c - - * don't assume only backward DN pointers in replies, allow forward - pointers too. This is quite large change, involves changing - parsing API all over the places. - - * internal: typedef dnsc_t and dnscc_t for [const] unsigned char, to - make function prototypes shorter to better fit on a single line. - - * in parsing routines, verify (assert) that the query type - is the one we can handle. - - * recognize names (and resolve them) as nameservers in dnsget. - - * when new request is submitted, don't send it immediately, but - add it into the head of the active queue with deadline=0. - This will allow us to tweak some query settings before it will - be processed. - Note API change: removed `now' argument from all dns_submit_*() - routines. - - * use single per-context user timer, not per-query. - Note API change: different user timer callback - - * add dnsc_salen field -- length of the socket address used - - * fix dns_set_opt(DNS_OPT_FLAGS) which didn't work before - - * allow to set some options for a context wich is open but with no - active queries - - -- Michael Tokarev Thu, 5 May 2005 23:14:29 +0400 - -udns (0.0.6) unstable; urgency=low - - * 0.0.6 release. - ALOT of changes all over. Keep 'em in CVS logs! - - -- Michael Tokarev Fri, 8 Apr 2005 19:51:38 +0400 - -udns (0.0.5) unstable; urgency=low - - * Initial Release. - * Provides 3 packages: - libudns0 - shared library - libudns-dev - development files and static library - udns-utils - dnsget, rblcheck - - -- Michael Tokarev Thu, 7 Apr 2005 00:05:24 +0400 - -Local variables: -mode: debian-changelog -End: diff --git a/deps/udns/debian/control b/deps/udns/debian/control deleted file mode 100644 index 5ae3fa07b11..00000000000 --- a/deps/udns/debian/control +++ /dev/null @@ -1,33 +0,0 @@ -Source: udns -Priority: optional -Maintainer: Michael Tokarev -Build-Depends: debhelper (>= 4.0.0) -Standards-Version: 3.7.2 - -Package: libudns0 -Section: libs -Architecture: any -Depends: ${shlibs:Depends} -Description: async-capable DNS stub resolver library - libudns0 package provides libudns shared library needed - to run programs using it - -Package: libudns-dev -Section: libdevel -Architecture: any -Depends: libudns0 (= ${Source-Version}) -Description: async-capable DNS stub resolver library, development files - This package provides development files needed - to build programs using udns library - -Package: udns-utils -Section: net -Architecture: any -Depends: ${shlibs:Depends} -Conflicts: rblcheck -Description: Several DNS-related utilities built on top of udns library - This package includes the following utilities: - dnsget - a simple DNS query tool, like `host' or `dig' for usage from - a command line, and dnsip, dnsname etc for usage in scripts - rblcheck - DNSBL (rbl) checker - All the utilities are built using udns library diff --git a/deps/udns/debian/copyright b/deps/udns/debian/copyright deleted file mode 100644 index 3d6c9c2bae5..00000000000 --- a/deps/udns/debian/copyright +++ /dev/null @@ -1,23 +0,0 @@ -This is udns, written and maintained by Michael Tokarev - -The original source can always be found at: - http://www.corpit.ru/mjt/udns.html - -Copyright (C) 2005,2006,2007 Michael Tokarev - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Lesser Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -On Debian systems, the complete text of the GNU Lesser General -Public License can be found in `/usr/share/common-licenses/LGPL'. diff --git a/deps/udns/debian/rules b/deps/udns/debian/rules deleted file mode 100755 index 6a5a46f1f1a..00000000000 --- a/deps/udns/debian/rules +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 -export DH_COMPAT=4 - -CFLAGS = -Wall -W -Wmissing-prototypes -g -CDEFS = -DHAVE_POOL - -INSTALL = install -INSTALL_PROGRAM = $(INSTALL) -p -INSTALL_DATA = $(INSTALL) -p -m0644 - -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 -else - CFLAGS += -O2 -endif -ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) - INSTALL_PROGRAM += -s -endif -ifeq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) -# CDEFS += -DNDEBUG -endif - -SOVER = 0 - -config.h: ./configure Makefile.in - dh_testdir - ./configure --enable-ipv6 - -build: build-stamp -build-stamp: config.h - dh_testdir - $(MAKE) CFLAGS="$(CFLAGS)" SOVER=$(SOVER) \ - staticlib sharedlib rblcheck_s dnsget_s - mv -f dnsget_s dnsget - mv -f rblcheck_s rblcheck - mv -f libudns_s.so libudns.so - echo - touch $@ - -clean: - dh_testdir - rm -f build-stamp - if [ -f Makefile ]; then $(MAKE) distclean; fi - dh_clean - -install: build - dh_testdir - dh_testroot - dh_clean - dh_installdirs - dh_installdocs -A NEWS - -# libudns - dh_install -plibudns$(SOVER) libudns.so.$(SOVER) usr/lib - -# libudns-dev - dh_install -plibudns-dev libudns.a libudns.so usr/lib - dh_install -plibudns-dev udns.h usr/include - dh_installman -plibudns-dev udns.3 - dh_installdocs -plibudns-dev TODO NOTES - dh_installexamples -plibudns-dev ex-rdns.c - -# udns-utils - dh_install -pudns-utils dnsget rblcheck usr/bin - dh_installman -pudns-utils dnsget.1 rblcheck.1 - -binary-indep: build install - -binary-arch: build install - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_strip - dh_compress - dh_fixperms - dh_makeshlibs -V - dh_installdeb - dh_shlibdeps -L libudns$(SOVER) -l . - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install diff --git a/deps/udns/dnsget.1 b/deps/udns/dnsget.1 deleted file mode 100644 index 711f29769ef..00000000000 --- a/deps/udns/dnsget.1 +++ /dev/null @@ -1,182 +0,0 @@ -.\" $Id: dnsget.1,v 1.3 2005/04/20 00:55:34 mjt Exp $ -.\" dnsget manpage -.\" -.\" Copyright (C) 2005 Michael Tokarev -.\" This file is part of UDNS library, an async DNS stub resolver. -.\" -.\" This library is free software; you can redistribute it and/or -.\" modify it under the terms of the GNU Lesser General Public -.\" License as published by the Free Software Foundation; either -.\" version 2.1 of the License, or (at your option) any later version. -.\" -.\" This library is distributed in the hope that it will be useful, -.\" but WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" Lesser General Public License for more details. -.\" -.\" You should have received a copy of the GNU Lesser General Public -.\" License along with this library, in file named COPYING.LGPL; if not, -.\" write to the Free Software Foundation, Inc., 59 Temple Place, -.\" Suite 330, Boston, MA 02111-1307 USA - -.TH dnsget 1 "Apr 2005" "User Utilities" - -.SH NAME -dnsget \- DNS lookup utility - -.SH SYNOPSYS -.B dnsget -.RB [\| \-v \||\| \-q \|] -.RB [\| \-c -.IR class \|] -.RB [\| \-t -.IR type \|] -.RB [\| \-o -.IR option : value \] -.IR name \|.\|.\|. - -.SH DESCRIPTION -.B dnsget -is a simple command-line to perform DNS lookups, similar to -.BR host (1) -and -.BR dig (1). -It is useable for both interactive/debugging scenarious and -in scripts. -The program is implemented using -.BR udns (3) -library. - -.PP -By default, -.B dnsget -produces a human-readable output, similar to -.RS -.nf -alias.example.com. CNAME www.example.com. -www.example.com. A 192.168.1.1 -www.example.com. MX 10 mx.example.com. -.fi -.RE -which is just sufficient to see how a given name resolves. -Output format is controllable with -.B \-v -and -.B \-q -options -- the former increases verbosity level up to printing -the whole DNS contents of all packets sent and received, which -is suitable for debugging DNS problems, while the latter reduces -the level, making output more quiet, up to bare result with no -error messages, which is good for scripts. - -.SH OPTIONS - -The following options are recognized by -.BR dnsget : - -.TP -.B \-v -produce more detailed output. More -.BR \-v 's -means more details will be produced. With single -.BR \-v , dnsget -will print contents of all received DNS packets (in a readable format), -while with -.BR \-vv , -it will output all outgoing DNS packets too. - -.TP -.B \-q -the opposite for \fB\-v\fR -- produce less detailed output. -With single -.BR \-q , dnsget -will only show (decoded) data from final DNS resource records (RR), -while -.B \-qq -also suppresses error messages. - -.TP -\fB\-t \fItype\fR -request record(s) of the given type \fItype\fR. By default, -.B dnsget -will ask for IPv4 address (A) record, or for PTR record if the -argument in question is an IPv4 or IPv6 address. Recognized -types include A, AAAA, MX, TXT, CNAME, PTR, NS, SOA, ANY and -others. - -.TP -\fB\-c \fIclass\fR -request DNS record(s) of the given class \fIclass\fR. By -default -.B dnsget -uses IN class. Valid classes include IN, CH, HS, ANY. - -.TP -.B \-a -(compatibility option). Equivalent to setting query type to -.B ANY -and increasing verbosity level -.RB ( \-v ). - -.TP -.B \-C -(planned) - -.TP -.B \-x -(planned) - -.TP -\fB\-o \fIoption\fR:\fIvalue\fR -Set resolver option \fIoption\fR to the value \fIvalue\fR -(may be specified several times). The same as setting -.RB $ RES_OPTIONS -environment variable. The following options are recognized: -.RS -.TP -\fBtimeout\fR:\fIsec\fR -Set initial query timeout to \fIsec\fR. -.TP -\fBattempts\fR:\fInum\fR -(re)try every query \fInum\fR times before failing. -.TP -\fBudpbuf\fR:\fIbytes\fR -set DNS UDP buffer size to \fIbytes\fR bytes. Valid values -are from 512 to 65535. If \fIbytes\fR is greather than 512, -EDNS0 (RFC 2671) extensions will be used. -.TP -\fBport\fR:\fInum\fR -Use given UDP port number \fInum\fR instead of the default port 53 (domain). -.RE - -.TP -\fB\-n \fInameserver\fR -Use the given nameserver(s) (may be specified more than once) -instead of the default. Using this option has the same same effect as -.RB $ NSCACHEIP -or -.RB $ NAMESERVERS -environment variables, with the only difference that only IPv4 addresses -are recognized for now, and it is possible to specify names (which will -be resolved using default settings) instead of IP addresses. - -.TP -.B \-h -print short help and exit. - -.SH "RETURN VALUE" -When all names where resovled successefully, -.B dnsget -exits with zero exit status. If at least one name was not found, -.B dnsget -will exit with return code 100. If some other error occured during -name resolution, it will exit with code 99. In case of usage or -initialization error, -.B dnsget -will return 1. - -.SH "SEE ALSO" -.BR host (1) -.BR dig (1) -.BR resolv.conf (5) -.BR udns (3). diff --git a/deps/udns/dnsget.c b/deps/udns/dnsget.c deleted file mode 100644 index 68c5295bef7..00000000000 --- a/deps/udns/dnsget.c +++ /dev/null @@ -1,726 +0,0 @@ -/* $Id: dnsget.c,v 1.31 2007/01/08 01:14:44 mjt Exp $ - simple host/dig-like application using UDNS library - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#ifdef WINDOWS -#include -#include -#else -#include -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include "udns.h" - -#ifndef HAVE_GETOPT -# include "getopt.c" -#endif - -#ifndef AF_INET6 -# define AF_INET6 10 -#endif - -static char *progname; -static int verbose = 1; -static int errors; -static int notfound; - -/* verbosity level: - * <0 - bare result - * 0 - bare result and error messages - * 1 - readable result - * 2 - received packet contents and `trying ...' stuff - * 3 - sent and received packet contents - */ - -static void die(int errnum, const char *fmt, ...) { - va_list ap; - fprintf(stderr, "%s: ", progname); - va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); - else putc('\n', stderr); - fflush(stderr); - exit(1); -} - -static const char *dns_xntop(int af, const void *src) { - static char buf[6*5+4*4]; - return dns_ntop(af, src, buf, sizeof(buf)); -} - -struct query { - const char *name; /* original query string */ - unsigned char *dn; /* the DN being looked up */ - enum dns_type qtyp; /* type of the query */ -}; - -static void query_free(struct query *q) { - free(q->dn); - free(q); -} - -static struct query * -query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) { - struct query *q = malloc(sizeof(*q)); - unsigned l = dns_dnlen(dn); - unsigned char *cdn = malloc(l); - if (!q || !cdn) die(0, "out of memory"); - memcpy(cdn, dn, l); - q->name = name; - q->dn = cdn; - q->qtyp = qtyp; - return q; -} - -static enum dns_class qcls = DNS_C_IN; - -static void -dnserror(struct query *q, int errnum) { - if (verbose >= 0) - fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname, - dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum)); - if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA) - ++notfound; - else - ++errors; - query_free(q); -} - -static const unsigned char * -printtxt(const unsigned char *c) { - unsigned n = *c++; - const unsigned char *e = c + n; - if (verbose > 0) while(c < e) { - if (*c < ' ' || *c >= 127) printf("\\%02x", *c); - else if (*c == '\\' || *c == '"') printf("\\%c", *c); - else putchar(*c); - ++c; - } - else - fwrite(c, n, 1, stdout); - return e; -} - -static void -printhex(const unsigned char *c, const unsigned char *e) { - while(c < e) - printf("%02x", *c++); -} - -static unsigned char to_b64[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static void -printb64(const unsigned char *c, const unsigned char *e) { - while(c < e) { - putchar(to_b64[c[0] >> 2]); - if (c+1 < e) { - putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]); - if (c+2 < e) { - putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]); - putchar(to_b64[c[2] & 0x3f]); - } - else { - putchar(to_b64[(c[1] & 0xf) << 2]); - putchar('='); - break; - } - } - else { - putchar(to_b64[(c[0] & 0x3) << 4]); - putchar('='); - putchar('='); - break; - } - c += 3; - } -} - -static void -printdate(time_t time) { - struct tm *tm = gmtime(&time); - printf("%04d%02d%02d%02d%02d%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} - -static void -printrr(const struct dns_parse *p, struct dns_rr *rr) { - const unsigned char *pkt = p->dnsp_pkt; - const unsigned char *end = p->dnsp_end; - const unsigned char *dptr = rr->dnsrr_dptr; - const unsigned char *dend = rr->dnsrr_dend; - unsigned char *dn = rr->dnsrr_dn; - const unsigned char *c; - unsigned n; - - if (verbose > 0) { - if (verbose > 1) { - if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) { - printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n", - rr->dnsrr_cls, rr->dnsrr_dsz); - return; - } - n = printf("%s.", dns_dntosp(rr->dnsrr_dn)); - printf("%s%u\t%s\t%s\t", - n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t", - rr->dnsrr_ttl, - dns_classname(rr->dnsrr_cls), - dns_typename(rr->dnsrr_typ)); - } - else - printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ)); - } - - switch(rr->dnsrr_typ) { - - case DNS_T_CNAME: - case DNS_T_PTR: - case DNS_T_NS: - case DNS_T_MB: - case DNS_T_MD: - case DNS_T_MF: - case DNS_T_MG: - case DNS_T_MR: - if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr; - printf("%s.", dns_dntosp(dn)); - break; - - case DNS_T_A: - if (rr->dnsrr_dsz != 4) goto xperr; - printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]); - break; - - case DNS_T_AAAA: - if (rr->dnsrr_dsz != 16) goto xperr; - printf("%s", dns_xntop(AF_INET6, dptr)); - break; - - case DNS_T_MX: - c = dptr + 2; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; - printf("%d %s.", dns_get16(dptr), dns_dntosp(dn)); - break; - - case DNS_T_TXT: - /* first verify it */ - for(c = dptr; c < dend; c += n) { - n = *c++; - if (c + n > dend) goto xperr; - } - c = dptr; n = 0; - while (c < dend) { - if (verbose > 0) printf(n++ ? "\" \"":"\""); - c = printtxt(c); - } - if (verbose > 0) putchar('"'); - break; - - case DNS_T_HINFO: /* CPU, OS */ - c = dptr; - n = *c++; if ((c += n) >= dend) goto xperr; - n = *c++; if ((c += n) != dend) goto xperr; - c = dptr; - if (verbose > 0) putchar('"'); - c = printtxt(c); - if (verbose > 0) printf("\" \""); else putchar(' '); - printtxt(c); - if (verbose > 0) putchar('"'); - break; - - case DNS_T_WKS: - c = dptr; - if (dptr + 4 + 2 >= end) goto xperr; - printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]); - c = dptr + 5; - for (n = 0; c < dend; ++c, n += 8) { - if (*c) { - unsigned b; - for (b = 0; b < 8; ++b) - if (*c & (1 << (7-b))) printf(" %d", n + b); - } - } - break; - - case DNS_T_SRV: /* prio weight port targetDN */ - c = dptr; - c += 2 + 2 + 2; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; - c = dptr; - printf("%d %d %d %s.", - dns_get16(c+0), dns_get16(c+2), dns_get16(c+4), - dns_dntosp(dn)); - break; - - case DNS_T_NAPTR: /* order pref flags serv regexp repl */ - c = dptr; - c += 4; /* order, pref */ - for (n = 0; n < 3; ++n) - if (c >= dend) goto xperr; - else c += *c + 1; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; - c = dptr; - printf("%u %u", dns_get16(c+0), dns_get16(c+2)); - c += 4; - for(n = 0; n < 3; ++n) { - putchar(' '); - if (verbose > 0) putchar('"'); - c = printtxt(c); - if (verbose > 0) putchar('"'); - } - printf(" %s.", dns_dntosp(dn)); - break; - - case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */ - c = dptr; - if (c + 2 + 1 + 1 > dend) goto xperr; - printf("%d %d %d", dns_get16(c), c[2], c[3]); - c += 2 + 1 + 1; - if (c < dend) { - putchar(' '); - printb64(c, dend); - } - break; - - case DNS_T_SIG: - /* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */ - c = dptr; - c += 2 + 1 + 1 + 4 + 4 + 4 + 2; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; - printf("%d %u %u %u ", - dns_get16(dptr), dptr[2], dptr[3], dns_get32(dptr+4)); - printdate(dns_get32(dptr+8)); - putchar(' '); - printdate(dns_get32(dptr+12)); - printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn)); - printb64(c, dend); - break; - -#if 0 /* unused RR types? */ - case DNS_T_DS: - c = dptr; - if (c + 2 + 2 >= dend) goto xperr; - printf("%u %u %u ", dns_get16(c), c[2], c[3]); - printhex(c + 4, dend); - break; - - case DNS_T_NSEC: - c = dptr; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; - printf("%s.", dns_dntosp(dn)); - unfinished. - break; -#endif - - - case DNS_T_SOA: - c = dptr; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || - dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || - c + 4*5 != dend) - goto xperr; - dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); - printf("%s. ", dns_dntosp(dn)); - dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); - printf("%s. ", dns_dntosp(dn)); - printf("%u %u %u %u %u", - dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8), - dns_get32(dptr+12), dns_get32(dptr+16)); - break; - - case DNS_T_MINFO: - c = dptr; - if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || - dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || - c != dend) - goto xperr; - dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); - printf("%s. ", dns_dntosp(dn)); - dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); - printf("%s.", dns_dntosp(dn)); - break; - - case DNS_T_NULL: - default: - printhex(dptr, dend); - break; - } - putchar('\n'); - return; - -xperr: - printf("\n"); - ++errors; -} - -static int -printsection(struct dns_parse *p, int nrr, const char *sname) { - struct dns_rr rr; - int r; - if (!nrr) return 0; - if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr); - - p->dnsp_rrl = nrr; - while((r = dns_nextrr(p, &rr)) > 0) - printrr(p, &rr); - if (r < 0) printf("<>\n"); - return r; -} - -/* dbgcb will only be called if verbose > 1 */ -static void -dbgcb(int code, const struct sockaddr *sa, unsigned slen, - const unsigned char *pkt, int r, - const struct dns_query *unused_q, void *unused_data) { - struct dns_parse p; - const unsigned char *cur, *end; - int numqd; - - if (code > 0) { - printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt))); - printf(";; sending %d bytes query to ", r); - } - else - printf(";; received %d bytes response from ", r); - if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in)) - printf("%s port %d\n", - dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr), - htons(((struct sockaddr_in*)sa)->sin_port)); -#ifdef HAVE_IPv6 - else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6)) - printf("%s port %d\n", - dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr), - htons(((struct sockaddr_in6*)sa)->sin6_port)); -#endif - else - printf("<>\n", sa->sa_family); - if (code > 0 && verbose < 3) { - putchar('\n'); - return; - } - - if (code == -2) printf(";; reply from unexpected source\n"); - if (code == -5) printf(";; reply to a query we didn't sent (or old)\n"); - if (r < DNS_HSIZE) { - printf(";; short packet (%d bytes)\n", r); - return; - } - if (dns_opcode(pkt) != 0) - printf(";; unexpected opcode %d\n", dns_opcode(pkt)); - if (dns_tc(pkt) != 0) - printf(";; warning: TC bit set, probably incomplete reply\n"); - - printf(";; ->>HEADER<<- opcode: "); - switch(dns_opcode(pkt)) { - case 0: printf("QUERY"); break; - case 1: printf("IQUERY"); break; - case 2: printf("STATUS"); break; - default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break; - } - printf(", status: %s, id: %d, size: %d\n;; flags:", - dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r); - if (dns_qr(pkt)) printf(" qr"); - if (dns_rd(pkt)) printf(" rd"); - if (dns_ra(pkt)) printf(" ra"); - if (dns_aa(pkt)) printf(" aa"); - if (dns_tc(pkt)) printf(" tc"); - numqd = dns_numqd(pkt); - printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n", - numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt)); - if (numqd != 1) - printf(";; unexpected number of entries in QUERY section: %d\n", - numqd); - printf("\n;; QUERY SECTION (%d):\n", numqd); - cur = dns_payload(pkt); - end = pkt + r; - while(numqd--) { - if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 || - cur + 4 > end) { - printf("; invalid query section\n"); - return; - } - r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf)); - printf("%s%s\t%s\n", - r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t", - dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur))); - cur += 4; - } - - p.dnsp_pkt = pkt; - p.dnsp_cur = p.dnsp_ans = cur; - p.dnsp_end = end; - p.dnsp_qdn = NULL; - p.dnsp_qcls = p.dnsp_qtyp = 0; - p.dnsp_ttl = 0xffffffffu; - p.dnsp_nrr = 0; - - r = printsection(&p, dns_numan(pkt), "ANSWER"); - if (r == 0) - r = printsection(&p, dns_numns(pkt), "AUTHORITY"); - if (r == 0) - r = printsection(&p, dns_numar(pkt), "ADDITIONAL"); - putchar('\n'); -} - -static void dnscb(struct dns_ctx *ctx, void *result, void *data) { - int r = dns_status(ctx); - struct query *q = data; - struct dns_parse p; - struct dns_rr rr; - unsigned nrr; - unsigned char dn[DNS_MAXDN]; - const unsigned char *pkt, *cur, *end; - if (!result) { - dnserror(q, r); - return; - } - pkt = result; end = pkt + r; cur = dns_payload(pkt); - dns_getdn(pkt, &cur, end, dn, sizeof(dn)); - dns_initparse(&p, NULL, pkt, cur, end); - p.dnsp_qcls = p.dnsp_qtyp = 0; - nrr = 0; - while((r = dns_nextrr(&p, &rr)) > 0) { - if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; - if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && - (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ)) - ++nrr; - else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { - if (dns_getdn(pkt, &rr.dnsrr_dptr, end, - p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || - rr.dnsrr_dptr != rr.dnsrr_dend) { - r = DNS_E_PROTOCOL; - break; - } - else { - if (verbose == 1) { - printf("%s.", dns_dntosp(dn)); - printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf)); - } - dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn)); - } - } - } - if (!r && !nrr) - r = DNS_E_NODATA; - if (r < 0) { - dnserror(q, r); - free(result); - return; - } - if (verbose < 2) { /* else it is already printed by dbgfn */ - dns_rewind(&p, NULL); - p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp; - p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls; - while(dns_nextrr(&p, &rr)) - printrr(&p, &rr); - } - free(result); - query_free(q); -} - -int main(int argc, char **argv) { - int i; - int fd; - fd_set fds; - struct timeval tv; - time_t now; - char *ns[DNS_MAXSERV]; - int nns = 0; - struct query *q; - enum dns_type qtyp = 0; - struct dns_ctx *nctx = NULL; - - if (!(progname = strrchr(argv[0], '/'))) progname = argv[0]; - else argv[0] = ++progname; - - if (argc <= 1) - die(0, "try `%s -h' for help", progname); - - if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL))) - die(errno, "unable to initialize dns library"); - /* we keep two dns contexts: one may be needed to resolve - * nameservers if given as names, using default options. - */ - - while((i = getopt(argc, argv, "vqt:c:an:o:h")) != EOF) switch(i) { - case 'v': ++verbose; break; - case 'q': --verbose; break; - case 't': - if (optarg[0] == '*' && !optarg[1]) - i = DNS_T_ANY; - else if ((i = dns_findtypename(optarg)) <= 0) - die(0, "unrecognized query type `%s'", optarg); - qtyp = i; - break; - case 'c': - if (optarg[0] == '*' && !optarg[1]) - i = DNS_C_ANY; - else if ((i = dns_findclassname(optarg)) < 0) - die(0, "unrecognized query class `%s'", optarg); - qcls = i; - break; - case 'a': - qtyp = DNS_T_ANY; - ++verbose; - break; - case 'n': - if (nns >= DNS_MAXSERV) - die(0, "too many nameservers, %d max", DNS_MAXSERV); - ns[nns++] = optarg; - break; - case 'o': - if (dns_set_opts(NULL, optarg) != 0) - die(0, "invalid option string: `%s'", optarg); - break; - case 'h': - printf( -"%s: simple DNS query tool (using udns version %s)\n" -"Usage: %s [options] domain-name...\n" -"where options are:\n" -" -h - print this help and exit\n" -" -v - be more verbose\n" -" -q - be less verbose\n" -" -t type - set query type (A, AAA, PTR etc)\n" -" -c class - set query class (IN (default), CH, HS, *)\n" -" -a - equivalent to -t ANY -v\n" -" -n ns - use given nameserver(s) instead of default\n" -" (may be specified multiple times)\n" -" -o option:value - set resovler option (the same as setting $RES_OPTIONS):\n" -" timeout:sec - initial query timeout\n" -" attempts:num - number of attempt to resovle a query\n" -" ndots:num - if name has more than num dots, lookup it before search\n" -" port:num - port number for queries instead of default 53\n" -" udpbuf:num - size of UDP buffer (use EDNS0 if >512)\n" -" (may be specified more than once)\n" - , progname, dns_version(), progname); - return 0; - default: - die(0, "try `%s -h' for help", progname); - } - - argc -= optind; argv += optind; - if (!argc) - die(0, "no name(s) to query specified"); - - if (nns) { - /* if nameservers given as names, resolve them. - * We only allow IPv4 nameservers as names for now. - * Ok, it is easy enouth to try both AAAA and A, - * but the question is what to do by default. - */ - struct sockaddr_in sin; - int j, r = 0, opened = 0; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1)); - dns_add_serv(NULL, NULL); - for(i = 0; i < nns; ++i) { - if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) { - struct dns_rr_a4 *rr; - if (!opened) { - if (dns_open(nctx) < 0) - die(errno, "unable to initialize dns context"); - opened = 1; - } - rr = dns_resolve_a4(nctx, ns[i], 0); - if (!rr) - die(0, "unable to resolve nameserver %s: %s", - ns[i], dns_strerror(dns_status(nctx))); - for(j = 0; j < rr->dnsa4_nrr; ++j) { - sin.sin_addr = rr->dnsa4_addr[j]; - if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0) - break; - } - free(rr); - } - else - r = dns_add_serv_s(NULL, (struct sockaddr *)&sin); - if (r < 0) - die(errno, "unable to add nameserver %s", - dns_xntop(AF_INET, &sin.sin_addr)); - } - } - dns_free(nctx); - - fd = dns_open(NULL); - if (fd < 0) - die(errno, "unable to initialize dns context"); - - if (verbose > 1) - dns_set_dbgfn(NULL, dbgcb); - - for (i = 0; i < argc; ++i) { - char *name = argv[i]; - union { - struct in_addr addr; - struct in6_addr addr6; - } a; - unsigned char dn[DNS_MAXDN]; - enum dns_type l_qtyp = 0; - int abs; - if (dns_pton(AF_INET, name, &a.addr) > 0) { - dns_a4todn(&a.addr, 0, dn, sizeof(dn)); - l_qtyp = DNS_T_PTR; - abs = 1; - } -#ifdef HAVE_IPv6 - else if (dns_pton(AF_INET6, name, &a.addr6) > 0) { - dns_a6todn(&a.addr6, 0, dn, sizeof(dn)); - l_qtyp = DNS_T_PTR; - abs = 1; - } -#endif - else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs)) - die(0, "invalid name `%s'\n", name); - else - l_qtyp = DNS_T_A; - if (qtyp) l_qtyp = qtyp; - q = query_new(name, dn, l_qtyp); - if (abs) abs = DNS_NOSRCH; - if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q)) - dnserror(q, dns_status(NULL)); - } - - FD_ZERO(&fds); - now = 0; - while((i = dns_timeouts(NULL, -1, now)) > 0) { - FD_SET(fd, &fds); - tv.tv_sec = i; - tv.tv_usec = 0; - i = select(fd+1, &fds, 0, 0, &tv); - now = time(NULL); - if (i > 0) dns_ioevent(NULL, now); - } - - return errors ? 1 : notfound ? 100 : 0; -} diff --git a/deps/udns/ex-rdns.c b/deps/udns/ex-rdns.c deleted file mode 100644 index 4b176e77861..00000000000 --- a/deps/udns/ex-rdns.c +++ /dev/null @@ -1,113 +0,0 @@ -/* $Id: ex-rdns.c,v 1.8 2007/01/07 22:46:47 mjt Exp $ - parallel rDNS resolver example - read IP addresses from stdin, - write domain names to stdout - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "udns.h" - -static int curq; - -static const char *n2ip(const unsigned char *c) { - static char b[sizeof("255.255.255.255")]; - sprintf(b, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]); - return b; -} -static void dnscb(struct dns_ctx *ctx, struct dns_rr_ptr *rr, void *data) { - const char *ip = n2ip((unsigned char *)&data); - int i; - --curq; - if (rr) { - printf("%s", ip); - for(i = 0; i < rr->dnsptr_nrr; ++i) - printf(" %s", rr->dnsptr_ptr[i]); - putchar('\n'); - free(rr); - } - else - fprintf(stderr, "%s: %s\n", ip, dns_strerror(dns_status(ctx))); -} - -int main(int argc, char **argv) { - int c, t; - time_t now; - int maxq = 10; - struct pollfd pfd; - char linebuf[1024]; - char *eol; - int eof; - - if (dns_init(NULL, 1) < 0) { - fprintf(stderr, "unable to initialize dns library\n"); - return 1; - } - while((c = getopt(argc, argv, "m:r")) != EOF) switch(c) { - case 'm': maxq = atoi(optarg); break; - case 'r': - dns_set_opt(0, DNS_OPT_FLAGS, - dns_set_opt(0, DNS_OPT_FLAGS, -1) | DNS_NORD); - break; - default: return 1; - } - if (argc != optind) return 1; - - pfd.fd = dns_sock(0); - pfd.events = POLLIN; - now = time(NULL); - c = optind; - eof = 0; - while(curq || !eof) { - if (!eof && curq < maxq) { - union { struct in_addr a; void *p; } pa; - if (!fgets(linebuf, sizeof(linebuf), stdin)) { - eof = 1; - continue; - } - eol = strchr(linebuf, '\n'); - if (eol) *eol = '\0'; - if (!linebuf[0]) continue; - if (dns_pton(AF_INET, linebuf, &pa.a) <= 0) - fprintf(stderr, "%s: invalid address\n", linebuf); - else if (dns_submit_a4ptr(0, &pa.a, dnscb, pa.p) == 0) - fprintf(stderr, "%s: unable to submit query: %s\n", - linebuf, dns_strerror(dns_status(0))); - else - ++curq; - continue; - } - if (curq) { - t = dns_timeouts(0, -1, now); - t = poll(&pfd, 1, c * 1000); - now = time(NULL); - if (t) dns_ioevent(0, now); - } - } - return 0; -} diff --git a/deps/udns/getopt.c b/deps/udns/getopt.c deleted file mode 100644 index f5d476a5661..00000000000 --- a/deps/udns/getopt.c +++ /dev/null @@ -1,165 +0,0 @@ -/* $Id: getopt.c,v 1.2 2007/01/07 23:19:19 mjt Exp $ - * Simple getopt() implementation. - * - * Standard interface: - * extern int getopt(int argc, char *const *argv, const char *opts); - * extern int optind; current index in argv[] - * extern char *optarg; argument for the current option - * extern int optopt; the current option - * extern int opterr; to control error printing - * - * Some minor extensions: - * ignores leading `+' sign in opts[] (unemplemented GNU extension) - * handles optional arguments, in form "x::" in opts[] - * if opts[] starts with `:', will return `:' in case of missing required - * argument, instead of '?'. - * - * Compile with -DGETOPT_NO_OPTERR to never print errors internally. - * Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for - * error reporting (ignored with -DGETOPT_NO_OPTERR). - * Compile with -DGETOPT_CLASS=static to get static linkage. - * Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed - * with "my_", like my_getopt instead of getopt. - * Compile with -DTEST to get a test executable. - * - * Written by Michael Tokarev. Public domain. - */ - -#include - -#ifndef GETOPT_CLASS -# define GETOPT_CLASS -#endif -#ifdef GETOPT_MY -# define optarg my_optarg -# define optind my_optind -# define opterr my_opterr -# define optopt my_optopt -# define getopt my_getopt -#endif - -GETOPT_CLASS char *optarg /* = NULL */; -GETOPT_CLASS int optind = 1; -GETOPT_CLASS int opterr = 1; -GETOPT_CLASS int optopt; - -static char *nextc /* = NULL */; - -#if defined(GETOPT_NO_OPTERR) - -#define printerr(argv, msg) - -#elif defined(GETOPT_NO_STDIO) - -extern int write(int, void *, int); - -static void printerr(char *const *argv, const char *msg) { - if (opterr) { - char buf[64]; - unsigned pl = strlen(argv[0]); - unsigned ml = strlen(msg); - char *p; - if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) { - write(2, argv[0], pl); - p = buf; - } - else { - memcpy(buf, argv[0], ml); - p = buf + pl; - } - *p++ = ':'; *p++ = ' '; - memcpy(p, msg, ml); p += ml; - *p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' '; - *p++ = optopt; - *p++ = '\n'; - write(2, buf, p - buf); - } -} - -#else - -#include -static void printerr(char *const *argv, const char *msg) { - if (opterr) - fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt); -} - -#endif - -GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) { - char *p; - - optarg = 0; - if (*opts == '+') /* GNU extension (permutation) - isn't supported */ - ++opts; - - if (!optind) { /* a way to reset things */ - nextc = 0; - optind = 1; - } - - if (!nextc || !*nextc) { /* advance to the next argv element */ - /* done scanning? */ - if (optind >= argc) - return -1; - /* not an optional argument */ - if (argv[optind][0] != '-') - return -1; - /* bare `-' */ - if (argv[optind][1] == '\0') - return -1; - /* special case `--' argument */ - if (argv[optind][1] == '-' && argv[optind][2] == '\0') { - ++optind; - return -1; - } - nextc = argv[optind] + 1; - } - - optopt = *nextc++; - if (!*nextc) - ++optind; - p = strchr(opts, optopt); - if (!p || optopt == ':') { - printerr(argv, "illegal option"); - return '?'; - } - if (p[1] == ':') { - if (*nextc) { - optarg = nextc; - nextc = NULL; - ++optind; - } - else if (p[2] != ':') { /* required argument */ - if (optind >= argc) { - printerr(argv, "option requires an argument"); - return *opts == ':' ? ':' : '?'; - } - else - optarg = argv[optind++]; - } - } - return optopt; -} - -#ifdef TEST - -#include - -int main(int argc, char **argv) { - int c; - while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) { - case 'a': - case 'b': - case 'c': - printf("option %c %s\n", c, optarg ? optarg : "(none)"); - break; - default: - return -1; - } - for(c = optind; c < argc; ++c) - printf("non-opt: %s\n", argv[c]); - return 0; -} - -#endif diff --git a/deps/udns/inet_XtoX.c b/deps/udns/inet_XtoX.c deleted file mode 100644 index 174b8edc64b..00000000000 --- a/deps/udns/inet_XtoX.c +++ /dev/null @@ -1,327 +0,0 @@ -/* $Id: inet_XtoX.c,v 1.1 2006/12/04 01:55:39 mjt Exp $ - * Simple implementation of the following functions: - * inet_ntop(), inet_ntoa(), inet_pton(), inet_aton(). - * - * Differences from traditional implementaitons: - * o modifies destination buffers even on error return. - * o no fancy (hex, or 1.2) input support in inet_aton() - * o inet_aton() does not accept junk after an IP address. - * o inet_ntop(AF_INET) requires at least 16 bytes in dest, - * and inet_ntop(AF_INET6) at least 40 bytes - * (traditional inet_ntop() will try to fit anyway) - * - * Compile with -Dinet_XtoX_prefix=pfx_ to have pfx_*() instead of inet_*() - * Compile with -Dinet_XtoX_no_ntop or -Dinet_XtoX_no_pton - * to disable net2str or str2net conversions. - * - * #define inet_XtoX_prototypes and #include "this_file.c" - * to get function prototypes only (but not for inet_ntoa()). - * #define inet_XtoX_decl to be `static' for static visibility, - * or use __declspec(dllexport) or somesuch... - * - * Compile with -DTEST to test against stock implementation. - * - * Written by Michael Tokarev. Public domain. - */ - -#ifdef inet_XtoX_prototypes - -struct in_addr; - -#else - -#include - -#ifdef TEST - -# include -# include -# include -# include -# include -# include -# include -# undef inet_XtoX_prefix -# define inet_XtoX_prefix mjt_inet_ -# undef inet_XtoX_no_ntop -# undef inet_XtoX_no_pton - -#else /* !TEST */ - -struct in_addr { /* declare it here to avoid messing with headers */ - unsigned char x[4]; -}; - -#endif /* TEST */ - -#endif /* inet_XtoX_prototypes */ - -#ifndef inet_XtoX_prefix -# define inet_XtoX_prefix inet_ -#endif -#ifndef inet_XtoX_decl -# define inet_XtoX_decl /*empty*/ -#endif - -#define cc2_(x,y) cc2__(x,y) -#define cc2__(x,y) x##y -#define fn(x) cc2_(inet_XtoX_prefix,x) - -#ifndef inet_XtoX_no_ntop - -inet_XtoX_decl const char * -fn(ntop)(int af, const void *src, char *dst, unsigned size); - -#ifndef inet_XtoX_prototypes - -static int mjt_ntop4(const void *_src, char *dst, int size) { - unsigned i, x, r; - char *p; - const unsigned char *s = _src; - if (size < 4*4) /* for simplicity, disallow non-max-size buffer */ - return 0; - for (i = 0, p = dst; i < 4; ++i) { - if (i) *p++ = '.'; - x = r = s[i]; - if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; } - if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; } - *p++ = (char)(r + '0'); - } - *p = '\0'; - return 1; -} - -static char *hexc(char *p, unsigned x) { - static char hex[16] = "0123456789abcdef"; - if (x > 0x0fff) *p++ = hex[(x >>12) & 15]; - if (x > 0x00ff) *p++ = hex[(x >> 8) & 15]; - if (x > 0x000f) *p++ = hex[(x >> 4) & 15]; - *p++ = hex[x & 15]; - return p; -} - -static int mjt_ntop6(const void *_src, char *dst, int size) { - unsigned i; - unsigned short w[8]; - unsigned bs = 0, cs = 0; - unsigned bl = 0, cl = 0; - char *p; - const unsigned char *s = _src; - - if (size < 40) /* for simplicity, disallow non-max-size buffer */ - return 0; - - for(i = 0; i < 8; ++i, s += 2) { - w[i] = (((unsigned short)(s[0])) << 8) | s[1]; - if (!w[i]) { - if (!cl++) cs = i; - } - else { - if (cl > bl) bl = cl, bs = cs; - } - } - if (cl > bl) bl = cl, bs = cs; - p = dst; - if (bl == 1) - bl = 0; - if (bl) { - for(i = 0; i < bs; ++i) { - if (i) *p++ = ':'; - p = hexc(p, w[i]); - } - *p++ = ':'; - i += bl; - if (i == 8) - *p++ = ':'; - } - else - i = 0; - for(; i < 8; ++i) { - if (i) *p++ = ':'; - if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff))) - return mjt_ntop4(s - 4, p, size - (p - dst)); - p = hexc(p, w[i]); - } - *p = '\0'; - return 1; -} - -inet_XtoX_decl const char * -fn(ntop)(int af, const void *src, char *dst, unsigned size) { - switch(af) { - /* don't use AF_*: don't mess with headers */ - case 2: /* AF_INET */ if (mjt_ntop4(src, dst, size)) return dst; break; - case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break; - default: errno = EAFNOSUPPORT; return (char*)0; - } - errno = ENOSPC; - return (char*)0; -} - -inet_XtoX_decl const char * -fn(ntoa)(struct in_addr addr) { - static char buf[4*4]; - mjt_ntop4(&addr, buf, sizeof(buf)); - return buf; -} - -#endif /* inet_XtoX_prototypes */ -#endif /* inet_XtoX_no_ntop */ - -#ifndef inet_XtoX_no_pton - -inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst); -inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr); - -#ifndef inet_XtoX_prototypes - -static int mjt_pton4(const char *c, void *dst) { - unsigned char *a = dst; - unsigned n, o; - for (n = 0; n < 4; ++n) { - if (*c < '0' || *c > '9') - return 0; - o = *c++ - '0'; - while(*c >= '0' && *c <= '9') - if ((o = o * 10 + (*c++ - '0')) > 255) - return 0; - if (*c++ != (n == 3 ? '\0' : '.')) - return 0; - *a++ = (unsigned char)o; - } - return 1; -} - -static int mjt_pton6(const char *c, void *dst) { - unsigned short w[8], *a = w, *z, *i; - unsigned v, o; - const char *sc; - unsigned char *d = dst; - if (*c != ':') z = (unsigned short*)0; - else if (*++c != ':') return 0; - else ++c, z = a; - i = 0; - for(;;) { - v = 0; - sc = c; - for(;;) { - if (*c >= '0' && *c <= '9') o = *c - '0'; - else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10; - else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10; - else break; - v = (v << 4) | o; - if (v > 0xffff) return 0; - ++c; - } - if (sc == c) { - if (z == a && !*c) - break; - else - return 0; - } - if (*c == ':') { - if (a >= w + 8) - return 0; - *a++ = v; - if (*++c == ':') { - if (z) - return 0; - z = a; - if (!*++c) - break; - } - } - else if (!*c) { - if (a >= w + 8) - return 0; - *a++ = v; - break; - } - else if (*c == '.') { - if (a > w + 6) - return 0; - if (!mjt_pton4(sc, d)) - return 0; - *a++ = ((unsigned)(d[0]) << 8) | d[1]; - *a++ = ((unsigned)(d[2]) << 8) | d[3]; - break; - } - else - return 0; - } - v = w + 8 - a; - if ((v && !z) || (!v && z)) - return 0; - for(i = w; ; ++i) { - if (i == z) - while(v--) { *d++ = '\0'; *d++ = '\0'; } - if (i >= a) - break; - *d++ = (unsigned char)((*i >> 8) & 255); - *d++ = (unsigned char)(*i & 255); - } - return 1; -} - -inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) { - switch(af) { - /* don't use AF_*: don't mess with headers */ - case 2 /* AF_INET */: return mjt_pton4(src, dst); - case 10 /* AF_INET6 */: return mjt_pton6(src, dst); - default: errno = EAFNOSUPPORT; return -1; - } -} - -inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) { - return mjt_pton4(src, addr); -} - -#endif /* inet_XtoX_prototypes */ - -#endif /* inet_XtoX_no_pton */ - -#ifdef TEST - -int main(int argc, char **argv) { - int i; - char n0[16], n1[16]; - char p0[64], p1[64]; - int af = AF_INET; - int pl = sizeof(p0); - int r0, r1; - const char *s0, *s1; - - while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) { - case '4': af = AF_INET; break; - case '6': af = AF_INET6; break; - case 'a': case 'p': pl = atoi(optarg); break; - default: return 1; - } - for(i = optind; i < argc; ++i) { - char *a = argv[i]; - - printf("%s:\n", a); - r0 = inet_pton(af, a, n0); - printf(" p2n stock: %s\n", - (r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0)))); - r1 = fn(pton)(af, a, n1); - printf(" p2n this : %s\n", - (r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1)))); - - if ((r0 > 0) != (r1 > 0) || - (r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0)) - printf(" DIFFER!\n"); - - s0 = inet_ntop(af, n1, p0, pl); - printf(" n2p stock: %s\n", s0 ? s0 : "(inval)"); - s1 = fn(ntop)(af, n1, p1, pl); - printf(" n2p this : %s\n", s1 ? s1 : "(inval)"); - if ((s0 != 0) != (s1 != 0) || - (s0 && s1 && strcmp(s0, s1) != 0)) - printf(" DIFFER!\n"); - - } - return 0; -} - -#endif /* TEST */ diff --git a/deps/udns/rblcheck.1 b/deps/udns/rblcheck.1 deleted file mode 100644 index 0e427e43955..00000000000 --- a/deps/udns/rblcheck.1 +++ /dev/null @@ -1,151 +0,0 @@ -.\" $Id: rblcheck.1,v 1.1 2005/04/24 23:14:23 mjt Exp $ -.\" rblckeck manpage -.\" -.\" Copyright (C) 2005 Michael Tokarev -.\" This file is part of UDNS library, an async DNS stub resolver. -.\" -.\" This library is free software; you can redistribute it and/or -.\" modify it under the terms of the GNU Lesser General Public -.\" License as published by the Free Software Foundation; either -.\" version 2.1 of the License, or (at your option) any later version. -.\" -.\" This library is distributed in the hope that it will be useful, -.\" but WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" Lesser General Public License for more details. -.\" -.\" You should have received a copy of the GNU Lesser General Public -.\" License along with this library, in file named COPYING.LGPL; if not, -.\" write to the Free Software Foundation, Inc., 59 Temple Place, -.\" Suite 330, Boston, MA 02111-1307 USA - -.TH rblckeck 1 "Apr 2005" "User Utilities" - -.SH NAME -rblckeck \- DNSBL lookup utility - -.SH SYNOPSYS -.B rblcheck -.RB [\| \-s -.IR zone \|] -.RB [\| \-S -.IR zone\-file \|] -.RB [\| \-c \|] -.RB [\| \-tmvq \|] -.RB [\| \-n -.IR nsaddr \|] -.IR address \|.\|.\|. - -.SH DESCRIPTION -.B rblcheck -is a simple command-line to perform DNSBL (DNS-based blocklists) lookups. -For every IP address (or a name, in which case it will be resolved to an -address first), the utility verifies whenever it is listed in a (list of) -DNS blocklists specified with -.B \-s -or -.B \-S -options, optionally obtains text assotiated with the listing (usually it -is either some description about the reason of the listing or an URL -referring to such a description), and displays results on standard output. -.PP -The program is implemented on top of -.BR udns (3) -library. - -.SH OPTIONS - -The following options are recognized by -.BR rblcheck : - -.TP -.B \-s \fIzone\fR -add the given \fIzone\fR DNSBL name to the list of active zones. -.TP -.B \-S \fIzone-file\fR -add list of zones from the named \fIzone-file\fR to the list of -active zones (the file specifies one zone as the first word on a -line, empty lines and lines starting with `#' character are ignored). -.TP -.B \-c -reset active zone list. -.TP -.B \-v -be more verbose, produce more detailed output. -.TP -.B \-q -the opposite for \fB\-v\fR -- produce less detailed output. -.TP -.B \-t -obtain text for listed addresses. -.TP -.B \-n \fInsaddr\fR -Use the given nameserver (given as IPv4 or IPv6 address) instead of the -default. The same effect may be achieved by setting $NSCACHEIP environment -variable. -.TP -.B \-m -stop after first hit, ie after the first address which is found to be -listed. - -.TP -.B \-h -print short help and exit. - -.PP -If no -.BR \-s , -.BR \-S -and -.B \-c -options are given, -.B rblcheck -will try to obtain list of zones using $RBLCHECK_ZONES environment variable, -or ~/.rblcheckrc, or /etc/rblckechrc files, in that order. If no zones are -found, it will exit unsuccessefully. - -.SH "RETURN VALUE" -When no addresses given are listed and no errors occured, -.B rblcheck -exits with code 0. If at least one address is listed, -.B rblcheck -returns 100. In case of DNS errors, -.B rblcheck -returns 2. - -.SH ENVIRONMENT - -.TP -.B $RBLCHECK_ZONES -if no -.BR \-s , -.B \-S -or -.B \-c -option is given, -.B rblcheck -tries this variable to obtain list of DNSBL zones to check against. - -.SH FILES - -.TP -$HOME/.rblcheckrc and /etc/rblcheckrc -if no -.BR \-s , -.B \-S -or -.B \-c -option is given, and no $RBLCHECK_ZONES environment variable is set, -.B rblcheck -will try the two files (the first one that exists) to obtain list of -DNSBL zones to check against. -Each line specifies one zone (only first word in each line is used). -Empty lines and lines starting with `#' character are ignored. - -.SH "SEE ALSO" -.BR dnsget (1) -.BR resolv.conf (5) -.BR udns (3). - -.SH AUTHOR -This program and manual pages are written by Michael Tokarev. diff --git a/deps/udns/rblcheck.c b/deps/udns/rblcheck.c deleted file mode 100644 index 1820d1c5df3..00000000000 --- a/deps/udns/rblcheck.c +++ /dev/null @@ -1,377 +0,0 @@ -/* $Id: rblcheck.c,v 1.14 2007/01/10 02:52:51 mjt Exp $ - dnsbl (rbl) checker application - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include -#include -#include -#ifdef WINDOWS -# include -#else -# include -# include -# include -# include -#endif -#include -#include -#include -#include "udns.h" - -#ifndef HAVE_GETOPT -# include "getopt.c" -#endif - -static const char *version = "udns-rblcheck 0.2"; -static char *progname; - -static void error(int die, const char *fmt, ...) { - va_list ap; - fprintf(stderr, "%s: ", progname); - va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - putc('\n', stderr); - fflush(stderr); - if (die) - exit(1); -} - -struct rblookup { - struct ipcheck *parent; - struct in_addr key; - const char *zone; - struct dns_rr_a4 *addr; - struct dns_rr_txt *txt; -}; - -struct ipcheck { - const char *name; - int naddr; - int listed; - struct rblookup *lookup; -}; - -#define notlisted ((void*)1) - -static int nzones, nzalloc; -static const char **zones; - -static int do_txt; -static int stopfirst; -static int verbose = 1; -/* verbosity level: - * <0 - only bare As/TXTs - * 0 - what RBL result - * 1(default) - what is listed by RBL: result - * 2 - what is[not ]listed by RBL: result, name lookups - */ - -static int listed; -static int failures; - -static void *ecalloc(int size, int cnt) { - void *t = calloc(size, cnt); - if (!t) - error(1, "out of memory"); - return t; -} - -static void addzone(const char *zone) { - if (nzones >= nzalloc) { - const char **zs = (const char**)ecalloc(sizeof(char*), (nzalloc += 16)); - if (zones) { - memcpy(zs, zones, nzones * sizeof(char*)); - free(zones); - } - zones = zs; - } - zones[nzones++] = zone; -} - -static int addzonefile(const char *fname) { - FILE *f = fopen(fname, "r"); - char linebuf[2048]; - if (!f) - return 0; - while(fgets(linebuf, sizeof(linebuf), f)) { - char *p = linebuf, *e; - while(*p == ' ' || *p == '\t') ++p; - if (*p == '#' || *p == '\n') continue; - e = p; - while(*e && *e != ' ' && *e != '\t' && *e != '\n') - ++e; - *e = '\0'; - addzone(p); - } - fclose(f); - return 1; -} - -static void dnserror(struct rblookup *ipl, const char *what) { - char buf[4*4]; - error(0, "unable to %s for %s (%s): %s", - what, dns_ntop(AF_INET, &ipl->key, buf, sizeof(buf)), - ipl->zone, dns_strerror(dns_status(0))); - ++failures; -} - -static void display_result(struct ipcheck *ipc) { - int j; - struct rblookup *l, *le; - char buf[4*4]; - if (!ipc->naddr) return; - for (l = ipc->lookup, le = l + nzones * ipc->naddr; l < le; ++l) { - if (!l->addr) continue; - if (verbose < 2 && l->addr == notlisted) continue; - if (verbose >= 0) { - dns_ntop(AF_INET, &l->key, buf, sizeof(buf)); - if (ipc->name) printf("%s[%s]", ipc->name, buf); - else printf("%s", buf); - } - if (l->addr == notlisted) { - printf(" is NOT listed by %s\n", l->zone); - continue; - } - else if (verbose >= 1) - printf(" is listed by %s: ", l->zone); - else if (verbose >= 0) - printf(" %s ", l->zone); - if (verbose >= 1 || !do_txt) - for (j = 0; j < l->addr->dnsa4_nrr; ++j) - printf("%s%s", j ? " " : "", - dns_ntop(AF_INET, &l->addr->dnsa4_addr[j], buf, sizeof(buf))); - if (!do_txt) ; - else if (l->txt) { - for(j = 0; j < l->txt->dnstxt_nrr; ++j) { - unsigned char *t = l->txt->dnstxt_txt[j].txt; - unsigned char *e = t + l->txt->dnstxt_txt[j].len; - printf("%s\"", verbose > 0 ? "\n\t" : j ? " " : ""); - while(t < e) { - if (*t < ' ' || *t >= 127) printf("\\x%02x", *t); - else if (*t == '\\' || *t == '"') printf("\\%c", *t); - else putchar(*t); - ++t; - } - putchar('"'); - } - free(l->txt); - } - else - printf("%s", verbose > 0 ? "\n\t" : ""); - free(l->addr); - putchar('\n'); - } - free(ipc->lookup); -} - -static void txtcb(struct dns_ctx *ctx, struct dns_rr_txt *r, void *data) { - struct rblookup *ipl = data; - if (r) { - ipl->txt = r; - ++ipl->parent->listed; - } - else if (dns_status(ctx) != DNS_E_NXDOMAIN) - dnserror(ipl, "lookup DNSBL TXT record"); -} - -static void a4cb(struct dns_ctx *ctx, struct dns_rr_a4 *r, void *data) { - struct rblookup *ipl = data; - if (r) { - ipl->addr = r; - ++listed; - if (do_txt) { - if (dns_submit_a4dnsbl_txt(0, &ipl->key, ipl->zone, txtcb, ipl)) - return; - dnserror(ipl, "submit DNSBL TXT record"); - } - ++ipl->parent->listed; - } - else if (dns_status(ctx) != DNS_E_NXDOMAIN) - dnserror(ipl, "lookup DNSBL A record"); - else - ipl->addr = notlisted; -} - -static int -submit_a_queries(struct ipcheck *ipc, - int naddr, const struct in_addr *addr) { - int z, a; - struct rblookup *rl = ecalloc(sizeof(*rl), nzones * naddr); - ipc->lookup = rl; - ipc->naddr = naddr; - for(a = 0; a < naddr; ++a) { - for(z = 0; z < nzones; ++z) { - rl->key = addr[a]; - rl->zone = zones[z]; - rl->parent = ipc; - if (!dns_submit_a4dnsbl(0, &rl->key, rl->zone, a4cb, rl)) - dnserror(rl, "submit DNSBL A query"); - ++rl; - } - } - return 0; -} - -static void namecb(struct dns_ctx *ctx, struct dns_rr_a4 *rr, void *data) { - struct ipcheck *ipc = data; - if (rr) { - submit_a_queries(ipc, rr->dnsa4_nrr, rr->dnsa4_addr); - free(rr); - } - else { - error(0, "unable to lookup `%s': %s", - ipc->name, dns_strerror(dns_status(ctx))); - ++failures; - } -} - -static int submit(struct ipcheck *ipc) { - struct in_addr addr; - if (dns_pton(AF_INET, ipc->name, &addr) > 0) { - submit_a_queries(ipc, 1, &addr); - ipc->name = NULL; - } - else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc)) { - error(0, "unable to submit name query for %s: %s\n", - ipc->name, dns_strerror(dns_status(0))); - ++failures; - } - return 0; -} - -static void waitdns(struct ipcheck *ipc) { - struct timeval tv; - fd_set fds; - int c; - int fd = dns_sock(NULL); - time_t now = 0; - FD_ZERO(&fds); - while((c = dns_timeouts(NULL, -1, now)) > 0) { - FD_SET(fd, &fds); - tv.tv_sec = c; - tv.tv_usec = 0; - c = select(fd+1, &fds, NULL, NULL, &tv); - now = time(NULL); - if (c > 0) - dns_ioevent(NULL, now); - if (stopfirst && ipc->listed) - break; - } -} - -int main(int argc, char **argv) { - int c; - struct ipcheck ipc; - char *nameserver = NULL; - int zgiven = 0; - - if (!(progname = strrchr(argv[0], '/'))) progname = argv[0]; - else argv[0] = ++progname; - - while((c = getopt(argc, argv, "hqtvms:S:cn:")) != EOF) switch(c) { - case 's': ++zgiven; addzone(optarg); break; - case 'S': - ++zgiven; - if (addzonefile(optarg)) break; - error(1, "unable to read zonefile `%s'", optarg); - case 'c': ++zgiven; nzones = 0; break; - case 'q': --verbose; break; - case 'v': ++verbose; break; - case 't': do_txt = 1; break; - case 'n': nameserver = optarg; break; - case 'm': ++stopfirst; break; - case 'h': - printf("%s: %s (udns library version %s).\n", - progname, version, dns_version()); - printf("Usage is: %s [options] address..\n", progname); - printf( -"Where options are:\n" -" -h - print this help and exit\n" -" -s service - add the service (DNSBL zone) to the serice list\n" -" -S service-file - add the DNSBL zone(s) read from the given file\n" -" -c - clear service list\n" -" -v - increase verbosity level (more -vs => more verbose)\n" -" -q - decrease verbosity level (opposite of -v)\n" -" -t - obtain and print TXT records if any\n" -" -m - stop checking after first address match in any list\n" -" -n ipaddr - use the given nameserver instead of the default\n" -"(if no -s or -S option is given, use $RBLCHECK_ZONES, ~/.rblcheckrc\n" -"or /etc/rblcheckrc in that order)\n" - ); - return 0; - default: - error(1, "use `%s -h' for help", progname); - } - - if (!zgiven) { - char *s = getenv("RBLCHECK_ZONES"); - if (s) { - char *k; - s = strdup(s); - for(k = strtok(s, " \t"); k; k = strtok(NULL, " \t")) - addzone(k); - free(s); - } - else { /* probably worthless on windows? */ - char *path; - char *home = getenv("HOME"); - if (!home) home = "."; - path = malloc(strlen(home) + 1 + sizeof(".rblcheckrc")); - sprintf(path, "%s/.rblcheckrc", home); - if (!addzonefile(path)) - addzonefile("/etc/rblcheckrc"); - free(path); - } - } - if (!nzones) - error(1, "no service (zone) list specified (-s or -S option)"); - - argv += optind; - argc -= optind; - - if (!argc) - return 0; - - if (dns_init(NULL, 0) < 0) - error(1, "unable to initialize DNS library: %s", strerror(errno)); - if (nameserver) { - dns_add_serv(NULL, NULL); - if (dns_add_serv(NULL, nameserver) < 0) - error(1, "wrong IP address for a nameserver: `%s'", nameserver); - } - if (dns_open(NULL) < 0) - error(1, "unable to initialize DNS library: %s", strerror(errno)); - - for (c = 0; c < argc; ++c) { - if (c && (verbose > 1 || (verbose == 1 && do_txt))) putchar('\n'); - memset(&ipc, 0, sizeof(ipc)); - ipc.name = argv[c]; - submit(&ipc); - waitdns(&ipc); - display_result(&ipc); - if (stopfirst > 1 && listed) break; - } - - return listed ? 100 : failures ? 2 : 0; -} diff --git a/deps/udns/udns.3 b/deps/udns/udns.3 deleted file mode 100644 index f580add5364..00000000000 --- a/deps/udns/udns.3 +++ /dev/null @@ -1,1351 +0,0 @@ -.\" $Id: udns.3,v 1.32 2007/01/15 21:19:08 mjt Exp $ -.\" udns library manpage -.\" -.\" Copyright (C) 2005 Michael Tokarev -.\" This file is part of UDNS library, an async DNS stub resolver. -.\" -.\" This library is free software; you can redistribute it and/or -.\" modify it under the terms of the GNU Lesser General Public -.\" License as published by the Free Software Foundation; either -.\" version 2.1 of the License, or (at your option) any later version. -.\" -.\" This library is distributed in the hope that it will be useful, -.\" but WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" Lesser General Public License for more details. -.\" -.\" You should have received a copy of the GNU Lesser General Public -.\" License along with this library, in file named COPYING.LGPL; if not, -.\" write to the Free Software Foundation, Inc., 59 Temple Place, -.\" Suite 330, Boston, MA 02111-1307 USA - -.TH udns 3 "Jan 2007" "Library Functions" - -.SH NAME -udns \- stub DNS resolver library - -.SH SYNOPSYS -.nf -#include -struct \fBdns_ctx\fR; -struct \fBdns_query\fR; -extern struct dns_ctx \fBdns_defctx\fR; -struct dns_ctx *\fIctx\fR; -typedef void \fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR); -typedef int -\fBdns_parse_fn\fR(const unsigned char *\fIqnd\fR, - const unsigned char *\fIpkt\fR, - const unsigned char *\fIcur\fR, - const unsigned char *\fIend\fR, - void **\fIresultp\fR); - -\fBcc\fR ... -l\fBudns\fR -.fi - -.SH DESCRIPTION - -.PP -The DNS library, \fBudns\fR, implements thread-safe stub DNS resolver -functionality, which may be used both traditional, syncronous way -and asyncronously, with application-supplied event loop. - -.PP -While DNS works with both TCP and UDP, performing UDP query first and -if the result does not fit in UDP buffer (512 bytes max for original -DNS protocol), retrying the query over TCP, the library uses UDP only, -but uses EDNS0 (RFC2671) extensions which allows larger UDP buffers. - -.PP -The library uses single UDP socket to perform all operations even when -asking multiple nameservers. This way, it is very simple to use the -library in asyncronous event-loop applications: an application should -add only single socket to the set of filedescriptors it monitors for I/O. - -.PP -The library uses two main objects, \fIresolver context\fR of type -\fBstruct\ dns_ctx\fR, and \fIquery structure\fR of type -\fBstruct\ dns_query\fR, both are opaque for an application. -Resolver context holds global information about the resolver, -such as list of nameservers to use, list of active requests and the like. -Query objects holds information about a single DNS query in progress and -are allocated/processed/freed by the library. Pointer to query structure -may be treated as an identifier of an in-progress query and may be used -to cancel the asyncronous query or to wait for it to complete. - -.PP -Asyncronous interface works as follows. An application initializes -resolver context, submits any number of queries for it using one of -supplied \fBdns_submit_\fIXXX\fR() routines (each return the query -identifier as pointer to query structure), waits for input on the -UDP socket used by the library, and gives some control to the library -by calling \fBdns_ioevent\fR() and \fBdns_timeouts\fR() routines when -appropriate. The library performs all necessary processing and executes -application supplied callback routine when a query completes (either -successefully or not), giving it the result if any, pointer to the -resolver context (from which completion status may be obtained), and -the data pointer supplied by an application when the query has been -submitted. When submitting a query, an application requests how to -handle the reply -- to either return raw DNS reply packet for its -own low-level processing, or it may provide an address of \fIparsing -routine\fR of type \fBdns_parse_fn\fR to perform conversion of on-wire -format into easy to use data structure (the library provides parsing -routines for several commonly used resource record types, as well as -type-safe higher-level inteface that requests parsing automatically). -The I/O monitoring and timeout handling may be either traditional -select() or poll() based, or any callback-driven technique may be -used. - -.PP -Additionally, the library provides traditional syncronous interface, -which may be intermixed with asyncronous calls (during syncronous -query processing, other asyncronous queries for the same resolver -context continued to be processed as usual). An application uses -one of numerous \fBdns_resolve_\fIXXX\fR() routines provided by the -library to perform a query. As with asyncronous interface, an -application may either request to return raw DNS packet or type-specific -data structure by providing the parsing routine to handle the reply. -Every routine from \fBdns_resolve_\fIXXX\fR() series return pointer -to result or NULL in case of any error. Query completion status -(or length of the raw DNS packet) is available from the resolver -context using \fBdns_status\fR() routine, the same way as for the -asyncronous interface. - -.PP -Internally, library uses on-wire format of domain names, referred -to as \fIDN format\fR in this manual page. This is a series of domain -\fIlabels\fR whith preceeding length byte, terminated by zero-length -label wich is integral part of the DN format. There are several routines -provided to convert from traditional asciiz string to DN and back. -Higher-level type-specific query interface hides the DN format from -an application. - -.SH "COMMON DEFINITIONS" - -.PP -Every DNS Resource Record (RR) has a \fItype\fR and a \fIclass\fR. -The library defines several integer constants, \fBDNS_C_\fIXXX\fR and -\fBDNS_T_\fIXXX\fR, to use as symbolic names for RR classes and types, -such as \fBDNS_C_IN\fR for Internet class, \fBDNS_T_A\fR for IPv4 -address record type and so on. See udns.h header file for complete list -of all such constants. - -.PP -The following constants are defined in udns.h header file: -.IP "\fBDNS_MAXDN\fR (255 bytes)" -Maximum length of the domain name in internal (on-wire) DN format. -.IP "\fBDNS_MAXLABEL\fR (63 bytes)" -Maximum length of a single label in DN format. -.IP "\fBDNS_MAXNAME\fR (1024 bytes)" -Maximum length of asciiz format of a domain name. -.IP "\fBDNS_HSIZE\fR (12 bytes)" -Size of header in DNS packet. -.IP "\fBDNS_PORT\fR (53)" -Default port to use when contacting a DNS server. -.IP "\fBDNS_MAXSERV\fR (6 servers)" -Maximum number of DNS servers to use. -.IP "\fBDNS_MAXPACKET\fR (512 bytes)" -Maximum length of DNS UDP packet as specified by original DNS protocol -.IP "\fBDNS_EDNS0PACKET\fR (4096 bytes)" -Default length of DNS UDP packet (with EDNS0 extensions) the library uses. -Note that recursive nameservers usually resides near the client asking them -to resolve names, e.g. on the same LAN segment or even on the same host, so -UDP packet fragmentation isn't a problem in most cases. Note also that -the size of actual packets will be as many bytes as actual reply size requires, -which is smaller than this value in almost all cases. - -.PP -Additionally, several constants are defined to simplify work with raw DNS -packets, such as DNS response codes (\fBDNS_R_\fIXXX\fR), DNS header layout -(\fBDNS_H_\fIXXX\fR) and others. Again, see udns.h for complete list. -Library error codes (\fBDNS_E_\fIXXX\fR) are described later in this -manual page. - -.SH "RESOLVER CONTEXT" - -.PP -Resolver context, of type \fBstruct\ dns_ctx\fR, is an object which is -opaque to an application. Several routines provided by the library -to initialize, copy and free resolver contexts. Most other high-level -routines in this library expects a pointer to resolver context, \fIctx\fR, -as the first argument. There is a default resolver context available, -named \fBdns_defctx\fR. When the context pointer \fIctx\fR passed to -a routine is NULL, \fBdns_defctx\fR is used. Several resolver contexts -may be active at the same time, for example, when an application is -multi-threaded and each thread uses resolver. -.PP -In order to use the library, an application should initialize and open -one or more resolver context objects. These are two separate actions, -performed by \fBdns_init\fR() (or \fBdns_reset\fR()), and \fBdns_open\fR(). -Between the two calls, an application is free to pefrorm additional -initialisation, such as setting custom nameservers, options or domain search -lists. Optionally, in case no additional custom initialisation is required, -\fBdns_init\fR() may open the context if \fIdo_open\fR argument (see below) -is non-zero. -.PP -When initializing resolver context, the library uses information from -system file /etc/resolv.conf (see \fBresolv.conf\fR(5)), consults -environment variables \fB$LOCALDOMAIN\fR, \fB$DNSCACHEIP\fR, -\fB$NAMESERVERS\fR and \fB$RES_OPTIONS\fR, and local host name to obtain -list of local nameservers, domain name search list and various resolver -options. -.PP -The following routines to initialize resolver context are available: -.PP -.nf -void \fBdns_reset\fR(\fIctx\fR) -int \fBdns_init\fR(\fIctx\fR, int \fIdo_open\fR) -.fi -.RS -\fBdns_reset\fR() resets a given resolver context to default values, -preparing it to be opened by \fBdns_open\fR(). -It is ok to call this routine against opened and active context - all active -queries will be dropped, sockets will be closed and so on. This routine -does not initialize any parameters from system configuration files, use -\fBdns_init\fR() for this. There's no error return - operation always -succeeds. \fBdns_init\fR() does everything \fBdns_reset\fR() does, -plus initializes various parameters of the context according to system -configuration and process environment variables. If \fIdo_open\fR is -non-zero, \fBdns_init\fR() calls \fIdns_open\fR(), so that the whole -library initialisation is performed in a single step. -.RE -.PP -.nf -struct dns_ctx *\fBdns_new\fR(struct dns_ctx *\fIcopy\fR) -void \fBdns_free\fR(\fIctx\fR) -.fi -.RS -\fBdns_new\fR() allocates new resolver context and copies all parameters -for a given resolver context \fIcopy\fR, or default context if \fIcopy\fR -is NULL, and returns pointer to the newly allocated context. The context -being copied should be initialized. -\fBdns_new\fR() may fail if there's no memory available to make a copy -of \fIcopy\fR, in which case the routine will return NULL pointer. -\fBdns_free\fR() is used to close assotiated socket and free resolver -context resources and cancelling (abandoming) all active queries -assotiated with it. It's an error to free \fBdns_defctx\fR, only -dynamically allocated contexts returned by \fBdns_new\fR() are allowed -to be freed by \fBdns_free\fR(). -.RE -.PP -.nf -int \fBdns_add_serv\fR(\fIctx\fR, const char *\fIservaddr\fR) -int \fBdns_add_serv_s\fR(\fIctx\fR, const struct sockaddr *\fIsa\fR) -int \fBdns_add_srch\fR(\fIctx\fR, const char *\fIsrch\fR) -.fi -.RS -Add an element to list of nameservers (\fBdns_add_serv\fR(), as -asciiz-string \fIservaddr\fR with an IP address of the nameserver, -and \fBdns_add_serv_s\fR(), as initialized socket address \fIsa\fR), -or search list (\fBdns_add_srch\fR(), as a pointer to domain name) -for the given context \fIctx\fR. If the last argument is a NULL -pointer, the corresponding list (search or nameserver) is reset -instead. Upon successeful completion, each routine returns new -number of elements in the list in question. On error, negative -value is returned and global variable \fBerrno\fR is set appropriately. -It is an error to call any of this functions if the context is -opened (after \fBdns_open\fR() or \fBdns_init\fR() with non-zero argument). -.RE -.PP -.nf -int \fBdns_set_opts\fR(\fIctx\fR, const char *\fIopts\fR) -.fi -.RS -set resolver context options from \fIopts\fR string, in the same way as -processing \fBoptions\fR statement in resolv.conf and \fB$RES_OPTIONS\fR -environment variable. -.RE -.PP -.nf -void \fBdns_set_opt\fR(\fIctx\fR, int \fIopt\fR, \fIval\fR) -.fi -.RS -.B TODO -The \fIflags\fR argument is a bitmask with the following bits defined: -.IP \fBDNS_NOSRCH\fR -do not perform domain name search in search list. -.IP \fBDNS_NORD\fR -do not request recursion when performing queries -(i.e. don't set RD flag in querues). -.IP \fBDNS_AAONLY\fR -request authoritative answers only (i.e. set AA -flag in queries). -.RE - -.PP -.nf -int \fBdns_open\fR(\fIctx\fR) -int \fBdns_sock\fR(const \fIctx\fR) -void \fBdns_close\fR(\fIctx\fR) -.fi -.RS -\fBdns_open\fR() opens the UDP socket used for queries if not already -open, and return assotiated filedescriptor (or negative value in case -of error). Before any query can be submitted, the context should be -opened using this routine. And before opening, the context should be -initialized. -\fBdns_sock\fR() return the UDP socket if open, or -1 if not. -\fBdns_close\fR() closes the UDP socket if it was open, and drops all active -queries if any. -.RE - -.PP -.nf -int \fBdns_active\fR(const \fIctx\fR) -.fi -.RS -return number of active queries queued for the given context -\fIctx\fR, or zero if none. -.RE - -.PP -.nf -int \fBdns_status\fR(const \fIctx\fR) -.fi -.RS -return status code from last operation. When using syncronous -interface, this is the query completion status of the last query. -With asyncronous interface, from within the callback routine, -this is the query completion status of the query for which the -callback is being called. When query submission fails, this -is the error code indicating failure reason. All error codes -are negative and are represented by \fBDNS_E_\fIXXX\fR constants -described below. -.RE - -.PP -.nf -void \fBdns_ioevent\fR(\fIctx\fR, time_t \fInow\fR) -.fi -.RS -this routine may be called by an application to process I/O -events on the UDP socket used by the library, as returned -by \fBdns_sock\fR(). The routine tries to receive incoming -UDP datagram from the socket and process it. The socket is -set up to be non-blocking, so it is safe to call the routine -even if there's no data to read. The routine will process -as many datagrams as are queued for the socket, so it is -safe to use it with either level-triggered or edge-triggered -I/O monitoring model. The \fInow\fR argument is either a -current time as returned by \fBtime\fR(), or 0, in which -case the routine will obtain current time by it's own. -.RE - -.PP -.nf -int \fBdns_timeouts\fR(\fIctx\fR, int \fImaxwait\fR, time_t \fInow\fR) -.fi -.RS -process any pending timeouts and return number of secounds -from current time (\fInow\fR if it is not 0) to the time when -the library wants the application to pass it control to process -more queued requests. In case when there are no requests pending, -this time is -1. The routine will not request a time larger than -\fImaxwait\fR secounds if it is greather or equal to zero. If -\fInow\fR is 0, the routine will obtain current time by it's own; -when it is not 0, it should contain current time as returned by -\fBtime\fR(). -.RE - -.PP -.nf -typedef void \fBdns_utm_fn\fR(\fIctx\fR, int \fItimeout\fR, void *\fIdata\fR) -void \fBdns_set_cbck\fR(\fIctx\fR, dns_utm_fn *\fIutmfn\fR, void *\fIdata\fR) -.fi -.RS -An application may use custom callback-based I/O multiplexing mechanism. -Usually such a mechanism have concept of a \fItimer\fR, and an ability -to register a timer event in a form of a callback routine which will -be executed after certain amount of time. In order to use such an -event mechanism, udns provides an ability to register and de-register -timer events necessary for internal processing using whatever event -mechanism an application uses. For this to work, it is possible to -assotiate a pointer to a routine that will perform necessary work for -(de)registering timer events with a given resolver context, and -udns will call that routine at appropriate times. Prototype of -such a routine is shown by \fBdns_utm_fn\fR typedef above. Libudns -assotiates single timer with resolver context. User-supplied \fIutmfn\fR -routine will be called by the library with the following arguments: -.IP "\fIctx\fR == NULL" -delete user timer, at context free time or when an application changes -user timer request routine using \fBdns_set_cbck\fR(); -.IP "\fIctx\fR != NULL, \fItimeout\fR < 0" -don't fire timer anymore, when there are no active requests; -.IP "\fIctx\fR != NULL, \fItimeout\fR == 0" -fire timer at the next possibility, but not immediately; -.IP "\fIctx\fR != NULL, \fItimeout\fR > 0" -fire timer after \fItimeout\fR seconds after now. -.PP -The \fIdata\fR argument passed to the routine will be the same -as passed to \fBdns_set_cbck\fR(). -.PP -When a timer expires, an application should call \fBdns_tmeouts\fR() -routine (see below). Non-callback timer usage is provided too. -.RE - -.PP -.B XXXX TODO: some more resolver context routines, like dns_set_dbgfn() etc. - -.SH "QUERY INTERFACE" - -.PP -There are two ways to perform DNS queries: traditional syncronous -way, when udns performs all the necessary processing and return -control to the application only when the query completes, and -asyncronous way, when an application submits one or more queries -to the library using given resolver context, and waits for completion -by monitoring filedescriptor used by library and calling library -routines to process input on that filedescriptor. Asyncronous mode -works with callback routines: an application supplies an address of -a routine to execute when the query completes, and a data pointer, -which is passed to the callback routine. - -.PP -Queries are submitted to the library in a form of \fBstruct\ dns_query\fR. -To perform asyncronous query, an application calls one of the -\fBdns_submit_\fIXXX\fR() rounines, and provides necessary information -for a callback, together with all the query parameters. -When the query completes, library will call application-supplied callback -routine, giving it the resolver context (wich holds query completion status), -dynamically allocated result (which will be either raw DNS packet or, if -applicatin requested parsing the result by specifying non-NULL parse routine, -ready-to-use type-specific structure), and a data pointer provided by an -application when it submitted the query. It is the application who's -responsible for freeing the result memory. -.PP -Generic query callback routine looks like this: -.nf -typedef void -\fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR) -.fi -Type-specific query interface expects similar form of callback -routine with the only difference in type of \fBresult\fR argument, -which will be pointer to specific data structure (decoded reply) -instead of this void pointer to raw DNS packet data. - -.PP -Result parsing routine looks like this: -.nf -typedef int -\fBdns_parse_fn\fR(const unsigned char *\fIqdn\fR, - const unsigned char *\fIpkt\fR, - const unsigned char *\fIcur\fR, - const unsigned char *\fIend\fR, - void **\fIresultp\fR); -.fi -When called by the library, the arguments are as follows: -\fIpkt\fR points to the start of the packet received; -\fIend\fR points past the end of the packet received; -\fIcur\fR points past the query DN in the query section of the -packet; -\fIqdn\fR points to the original query DN. -The routine should allocate a single buffer to hold the result, -parse the reply filling in the buffer, and return the buffer -using \fIresultp\fR argument. It returns 0 in case of error, -or udns error code (\fBDNS_E_\fIXXX\fR constants) in case of -error. -Note that by the time when the parse routine is called by the -library, packet is already verified to be a reply to the -original query, by matching query DN, query class and query type. - -.PP -Type-specific query inteface supplies necessary parsing routines -automatically. - -.PP -In case of error, query completion status as returned by -\fBdns_status\fR(\fIctx\fR), will contain one of the following values: -.IP "positive value" -length of raw DNS packet if parsing is not requested. -.IP 0 -the query was successeful and the \fIreply\fR points to type-specific -data structure. -.IP \fBDNS_E_TEMPFAIL\fR -temporary error, the resolver nameserver was not able to -process our query or timed out. -.IP \fBDNS_E_PROTOCOL\fR -protocol error, a nameserver returned malformed reply. -.IP \fBDNS_E_NXDOMAIN\fR -the domain name does not exist. -.IP \fBDNS_E_NODATA\fR -there is no data of requested type found. -.IP \fBDNS_E_NOMEM\fR -out of memory while processing request. -.IP \fBDNS_E_BADQUERY\fR -some aspect of the query (most common is the domain name in question) -is invalid, and the library can't even start a query. - -.PP -Library provides two series of routines which uses similar interface -- -one for asyncronous queries and another for syncronous queries. There -are two general low-level routines in each series to submit (asyncronous -interface) and resolve (syncronous interface) queries, as well as several -type-specific routines with more easy-to-use interfaces. To submit -an asyncronous query, use one of \fBdns_submit_\fIXXX\fR() routine, each -of which accepts query parameters, pointers to callback routine and to -callback data, and optional current time hint. Note type-specific -\fBdns_submit_\fIXXX\fR() routines expects specific type of the callback -routine as well, which accepts reply as a pointer to corresponding -structure, not a void pointer). Every \fBdns_submit_\fIXXX\fR() routine -return pointer to internal query structure of type struct\ dns_query, -used as an identifier for the given query. - -.PP -To resolve a query syncronously, use one of \fBdns_resolve_\fIXXX\fR() -routines, which accepts the same query parameters (but not the -callback pointers) as corresponding \fBdns_submit_\fIXXX\fR(), and -return the query result, which is the same as passed to the callback -routine in case of asyncronous interface. - -.PP -In either case, the result memory (if the query completed successefully) -is dynamically allocated and should be freed by an application. If -the query failed for any reason, the result will be NULL, and error -status will be available from \fBdns_status\fR(\fIctx\fR) routine -as shown above. - -.PP -.nf -struct dns_query * -\fBdns_submit_dn\fR(\fIctx\fR, - const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, - \fIparse\fR, \fIcbck\fR, \fIdata\fR) -struct dns_query * -\fBdns_submit_p\fR(\fIctx\fR, - const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, - \fIparse\fR, \fIcbck\fR, \fIdata\fR) - enum dns_class \fIqcls\fR; - enum dns_type \fIqtyp\fR; - int \fIflags\fR; - dns_parse_fn *\fIparse\fR; - dns_query_fn *\fIcbck\fR; - void *\fIdata\fR; -.fi -.RS -submit a query for processing for the given resolver context \fIctx\fR. -Two routines differs only in 3rd argument, which is domain name in -DN format (\fIdn\fR) or asciiz string (\fIname\fR). The query will be -performed for the given domain name, with type \fIqtyp\fR in class \fIqcls\fR, -using option bits in \fIflags\fR, using RR parsing routine pointed by -\fIparse\fR if not-NULL, and upon completion, \fIcbck\fR function will -be called with the \fIdata\fR argument. -In case of successeful query submission, -the routine return pointer to internal query structure which may be treated -as an identifier of the query as used by the library, and may be used as an -argument for \fBdns_cancel\fR() routine. In case of error, NULL will be -returned, and context error status (available using \fIdns_status\fR() routine) -will be set to corresponding error code, which in this case may be -DNS_E_BADQUERY if the \fIname\fR of \fIdn\fR is invalid, DNS_E_NOMEM if -there's no memory available to allocate query structure, or DNS_E_TEMPFAIL -if an internal error occured. -.RE - -.PP -.nf -void *\fBdns_resolve_dn\fR(\fIctx\fR, - const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR); -void *\fBdns_resolve_p\fR(\fIctx\fR, - const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR) - enum dns_class \fIqcls\fR; - enum dns_type \fIqtyp\fR; - int \fIflags\fR; - dns_parse_fn *\fIparse\fR; -.fi -.RS -syncronous interface. The routines perform all the steps necessary to resolve -the given query and return the result. If there's no positive result for any -reason, all the routines return NULL, and set context error status (available -using \fBdns_status\fR() routine) to indicate the error code. If the query -was successeful, context status code will contain either the length of the -raw DNS reply packet if \fIparse\fR argument was NULL (in which case the return -value is pointer to the reply DNS packet), or 0 (in which case the return value -is the result of \fIparse\fR routine). If the query successeful (return value -is not NULL), the memory returned was dynamically allocated by the library -and should be free()d by application after use. -.RE - -.PP -.nf -void *\fBdns_resolve\fR(\fIctx\fR, struct dns_query *\fIq\fR) -.fi -.RS -wait for the given query \fIq\fR, as returned by one of -\fBdns_submit_\fIXXX\fR() routines, for completion, and -return the result. The callback routine will not be called -for this query. After completion, the query identifier \fIq\fR -is not valid. Both \fBdns_resolve_dn\fR() and \fBdns_resolve_p\fR() -are just wrappers around corresponding submit routines and this -\fBdns_resolve\fR() routine. -.RE - -.PP -.nf -void \fBdns_cancel\fR(\fIctx\fR, struct dns_query *\fIq\fR) -.fi -.RS -cancel an active query \fIq\fR, without calling a callback routine. -After completion, the query identifier \fIq\fR is not valid. -.RE - -.SH "TYPE-SPECIFIC QUERIES" - -.PP -In addition to the generic low-level query interface, the library provides -a set of routines to perform specific queries in a type-safe manner, as -well as parsers for several well-known resource record types. The library -implements high-level interface for A, AAAA, PTR, MX and TXT records -and DNSBL and RHSBL functionality. These routines returns specific types -as result of a query, instead of raw DNS packets. The following types -and routines are available. - -.PP -.nf -struct \fBdns_rr_null\fR { - char *\fBdnsn_qname\fR; /* original query name */ - char *\fBdnsn_cname\fR; /* canonical name */ - unsigned \fBdnsn_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsn_nrr\fR; /* number of records in the set */ -}; -.fi -.PP -NULL RR set, used as a base for all other RR type structures. -Every RR structure as used by the library have four standard -fields as in struct\ \fBdns_rr_null\fR. - -.SS "IN A Queries" -.PP -.nf -struct \fBdns_rr_a4\fR { /* IN A RRset */ - char *\fBdnsa4_qname\fR; /* original query name */ - char *\fBdnsa4_cname\fR; /* canonical name */ - unsigned \fBdnsa4_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsa4_nrr\fR; /* number of addresses in the set */ - struct in_addr \fBdnsa4_addr\fR[]; /* array of addresses */ -}; -typedef void - \fBdns_query_a4_fn\fR(\fIctx\fR, struct dns_rr_a4 *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_a4\fB; -struct dns_query * -\fBdns_submit_a4\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR, - dns_query_a4_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_a4 * -\fBdns_resolve_a4\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR); -.fi -.PP -The \fBdns_rr_a4\fR structure holds a result of an \fBIN A\fR query, -which is an array of IPv4 addresses. Callback routine for IN A queries -expected to be of type \fBdns_query_a4_fn\fR, which expects pointer to -\fBdns_rr_a4\fR structure as query result instead of raw DNS packet. -The \fBdns_parse_a4\fR() is used to convert raw DNS reply packet into -\fBdns_rr_a4\fR structure (it is used internally and may be used directly too -with generic query interface). Routines \fBdns_submit_a4\fR() and -\fBdns_resolve_a4\fR() are used to perform A IN queries in a type-safe -manner. The \fIname\fR parameter is the domain name in question, and -\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical -interest (if the \fIname\fR is absolute, that is, it ends up with a dot, -DNS_NOSRCH flag will be set automatically). - -.SS "IN AAAA Queries" -.PP -.nf -struct \fBdns_rr_a6\fR { /* IN AAAA RRset */ - char *\fBdnsa6_qname\fR; /* original query name */ - char *\fBdnsa6_cname\fR; /* canonical name */ - unsigned \fBdnsa6_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsa6_nrr\fR; /* number of addresses in the set */ - struct in6_addr \fBdnsa6_addr\fR[]; /* array of addresses */ -}; -typedef void - \fBdns_query_a6_fn\fR(\fIctx\fR, struct dns_rr_a6 *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_a6\fB; -struct dns_query * -\fBdns_submit_a6\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR, - dns_query_a6_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_a6 * -\fBdns_resolve_a6\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR); -.fi -.PP -The \fBdns_rr_a6\fR structure holds a result of an \fBIN AAAA\fR query, -which is an array of IPv6 addresses. Callback routine for IN AAAA queries -expected to be of type \fBdns_query_a6_fn\fR, which expects pointer to -\fBdns_rr_a6\fR structure as query result instead of raw DNS packet. -The \fBdns_parse_a6\fR() is used to convert raw DNS reply packet into -\fBdns_rr_a6\fR structure (it is used internally and may be used directly too -with generic query interface). Routines \fBdns_submit_a6\fR() and -\fBdns_resolve_a6\fR() are used to perform AAAA IN queries in a type-safe -manner. The \fIname\fR parameter is the domain name in question, and -\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical -interest (if the \fIname\fR is absolute, that is, it ends up with a dot, -DNS_NOSRCH flag will be set automatically). - -.SS "IN PTR Queries" -.PP -.nf -struct \fBdns_rr_ptr\fR { /* IN PTR RRset */ - char *\fBdnsptr_qname\fR; /* original query name */ - char *\fBdnsptr_cname\fR; /* canonical name */ - unsigned \fBdnsptr_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsptr_nrr\fR; /* number of domain name pointers */ - char *\fBdnsptr_ptr\fR[]; /* array of domain name pointers */ -}; -typedef void - \fBdns_query_ptr_fn\fR(\fIctx\fR, struct dns_rr_ptr *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_ptr\fB; -struct dns_query * -\fBdns_submit_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR, - dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_ptr * -\fBdns_resolve_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR); -struct dns_query * -\fBdns_submit_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR, - dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_ptr * -\fBdns_resolve_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR); -.fi -.PP -The \fBdns_rr_ptr\fR structure holds a result of an IN PTR query, which -is an array of domain name pointers for a given IPv4 or IPv6 address. -Callback routine for IN PTR queries expected to be of type -\fBdns_query_ptr_fn\fR, which expects pointer to \fBdns_rr_ptr\fR -structure as query result instead of raw DNS packet. The \fBdns_parse_ptr\fR() -is used to convert raw DNS reply packet into \fBdns_rr_ptr\fR structure -(it is used internally and may be used directly too with generic query -interface). Routines \fBdns_submit_a4ptr\fR() and \fBdns_resolve_a4ptr\fR() -are used to perform IN PTR queries for IPv4 addresses in a type-safe -manner. Routines \fBdns_submit_a6ptr\fR() and \fBdns_resolve_a6ptr\fR() -are used to perform IN PTR queries for IPv6 addresses. - -.SS "IN MX Queries" -.PP -.nf -struct \fBdns_mx\fR { /* single MX record */ - int \fBpriority\fR; /* priority value of this MX */ - char *\fBname\fR; /* domain name of this MX */ -}; -struct \fBdns_rr_mx\fR { /* IN MX RRset */ - char *\fBdnsmx_qname\fR; /* original query name */ - char *\fBdnsmx_cname\fR; /* canonical name */ - unsigned \fBdnsmx_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsmx_nrr\fR; /* number of mail exchangers in the set */ - struct dns_mx \fBdnsmx_mx\fR[]; /* array of mail exchangers */ -}; -typedef void - \fBdns_query_mx_fn\fR(\fIctx\fR, struct dns_rr_mx *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_mx\fB; -struct dns_query * -\fBdns_submit_mx\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR, - dns_query_mx_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_mx * -\fBdns_resolve_mx\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR); -.fi -.PP -The \fBdns_rr_mx\fR structure holds a result of an IN MX query, which -is an array of mail exchangers for a given domain. Callback routine for IN MX -queries expected to be of type \fBdns_query_mx_fn\fR, which expects pointer to -\fBdns_rr_mx\fR structure as query result instead of raw DNS packet. -The \fBdns_parse_mx\fR() is used to convert raw DNS reply packet into -\fBdns_rr_mx\fR structure (it is used internally and may be used directly too -with generic query interface). Routines \fBdns_submit_mx\fR() and -\fBdns_resolve_mx\fR() are used to perform IN MX queries in a type-safe -manner. The \fIname\fR parameter is the domain name in question, and -\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical -interest (if the \fIname\fR is absolute, that is, it ends up with a dot, -DNS_NOSRCH flag will be set automatically). - -.SS "TXT Queries" -.PP -.nf -struct \fBdns_txt\fR { /* single TXT record */ - int \fBlen\fR; /* length of the text */ - unsigned char *\fBtxt\fR; /* pointer to the text */ -}; -struct \fBdns_rr_txt\fR { /* TXT RRset */ - char *\fBdnstxt_qname\fR; /* original query name */ - char *\fBdnstxt_cname\fR; /* canonical name */ - unsigned \fBdnstxt_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnstxt_nrr\fR; /* number of text records in the set */ - struct dns_txt \fBdnstxt_txt\fR[]; /* array of TXT records */ -}; -typedef void - \fBdns_query_txt_fn\fR(\fIctx\fR, struct dns_rr_txt *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_txt\fB; -struct dns_query * -\fBdns_submit_txt\fB(\fIctx\fR, const char *\fIname\fR, enum dns_class \fIqcls\fR, - int \fIflags\fR, dns_query_txt_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_txt * -\fBdns_resolve_txt\fB(\fIctx\fR, const char *\fIname\fR, - enum dns_class \fIqcls\fR, int \fIflags\fR); -.fi -.PP -The \fBdns_rr_txt\fR structure holds a result of a TXT query, which is an -array of text records for a given domain name. Callback routine for TXT -queries expected to be of type \fBdns_query_txt_fn\fR, which expects pointer -to \fBdns_rr_txt\fR structure as query result instead of raw DNS packet. -The \fBdns_parse_txt\fR() is used to convert raw DNS reply packet into -\fBdns_rr_txt\fR structure (it is used internally and may be used directly too -with generic query interface). Routines \fBdns_submit_txt\fR() and -\fBdns_resolve_txt\fR() are used to perform IN MX queries in a type-safe -manner. The \fIname\fR parameter is the domain name in question, and -\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical -interest (if the \fIname\fR is absolute, that is, it ends up with a dot, -DNS_NOSRCH flag will be set automatically). Note that each TXT string -is represented by \fBstruct\ dns_txt\fR, while zero-terminated (and the -len field of the structure does not include the terminator), may contain -embedded null characters -- content of TXT records is not interpreted -by the library in any way. - -.SS "SRV Queries" -.PP -.nf -struct \fBdns_srv\fR { /* single SRV record */ - int \fBpriority\fR; /* priority of the record */ - int \fBweight\fR; /* weight of the record */ - int \fBport\fR; /* the port number to connect to */ - char *\fBname\fR; /* target host name */ -}; -struct \fBdns_rr_srv\fR { /* SRV RRset */ - char *\fBdnssrv_qname\fR; /* original query name */ - char *\fBdnssrv_cname\fR; /* canonical name */ - unsigned \fBdnssrv_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnssrv_nrr\fR; /* number of text records in the set */ - struct dns_srv \fBdnssrv_srv\fR[]; /* array of SRV records */ -}; -typedef void - \fBdns_query_srv_fn\fR(\fIctx\fR, struct dns_rr_srv *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_srv\fB; -struct dns_query * -\fBdns_submit_srv\fB(\fIctx\fR, const char *\fIname\fR, const char *\fIservice\fR, const char *\fIprotocol\fR, - int \fIflags\fR, dns_query_txt_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_srv * -\fBdns_resolve_srv\fB(\fIctx\fR, const char *\fIname\fR, const char *\fIservice\fR, const char *\fIprotocol\fR, - int \fIflags\fR); -.fi -.PP -The \fBdns_rr_srv\fR structure holds a result of an IN SRV (rfc2782) query, -which is an array of servers (together with port numbers) which are performing -operations for a given \fIservice\fR using given \fIprotocol\fR on a target -domain \fIname\fR. Callback routine for IN SRV queries expected to be of type -\fBdns_query_srv_fn\fR, which expects pointer to \fBdns_rr_srv\fR structure as -query result instead of raw DNS packet. The \fBdns_parse_srv\fR() is used to -convert raw DNS reply packet into \fBdns_rr_srv\fR structure (it is used -internally and may be used directly too with generic query interface). -Routines \fBdns_submit_srv\fR() and \fBdns_resolve_srv\fR() are used to -perform IN SRV queries in a type-safe manner. The \fIname\fR parameter -is the domain name in question, \fIservice\fR and \fRprotocl\fR specifies the -service and the protocol in question (the library will construct query DN -according to rfc2782 rules) and may be NULL (in this case the library -assumes \fIname\fR parameter holds the complete SRV query), and -\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical -interest (if the \fIname\fR is absolute, that is, it ends up with a dot, -DNS_NOSRCH flag will be set automatically). - -.SS "NAPTR Queries" -.PP -.nf -struct \fBdns_naptr\fR { /* single NAPTR record */ - int \fBorder\fR; /* record order */ - int \fBpreference\fR; /* preference of this record */ - char *\fBflags\fR; /* application-specific flags */ - char *\fBservices\fR; /* service parameters */ - char *\fBregexp\fR; /* substitutional regular expression */ - char *\fBreplacement\fR; /* replacement string */ -}; -struct \fBdns_rr_naptr\fR { /* NAPTR RRset */ - char *\fBdnsnaptr_qname\fR; /* original query name */ - char *\fBdnsnaptr_cname\fR; /* canonical name */ - unsigned \fBdnsnaptr_ttl\fR; /* Time-To-Live (TTL) value */ - int \fBdnsnaptr_nrr\fR; /* number of text records in the set */ - struct dns_naptr \fBdnsnaptr_naptr\fR[]; /* array of NAPTR records */ -}; -typedef void - \fBdns_query_naptr_fn\fR(\fIctx\fR, struct dns_rr_naptr *\fIresult\fR, \fIdata\fR) -dns_parse_fn \fBdns_parse_naptr\fB; -struct dns_query * -\fBdns_submit_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR, - dns_query_txt_fn *\fIcbck\fR, \fIdata\fR); -struct dns_rr_naptr * -\fBdns_resolve_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR); -.fi -.PP -The \fBdns_rr_naptr\fR structure holds a result of an IN NAPTR (rfc3403) query. -Callback routine for IN NAPTR queries expected to be of type -\fBdns_query_naptr_fn\fR, expects pointer to \fBdns_rr_naptr\fR -structure as query result instead of raw DNS packet. -The \fBdns_parse_naptr\fR() is used to convert raw DNS reply packet into -\fBdns_rr_naptr\fR structure (it is used -internally and may be used directly too with generic query interface). -Routines \fBdns_submit_naptr\fR() and \fBdns_resolve_naptr\fR() are used to -perform IN NAPTR queries in a type-safe manner. The \fIname\fR parameter -is the domain name in question, and \fIflags\fR is query flags bitmask, -with one bit, DNS_NOSRCH, of practical interest (if the \fIname\fR is -absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set -automatically). - -.SS "DNSBL Interface" -.PP -A DNS-based blocklists, or a DNSBLs, are in wide use nowadays, especially -to protect mailservers from spammers. The library provides DNSBL interface, -a set of routines to perform queries against DNSBLs. Routines accepts an -IP address (IPv4 and IPv6 are both supported) and a base DNSBL zone as -query parameters, and returns either \fBdns_rr_a4\fR or \fBdns_rr_txt\fR -structure. Note that IPv6 interface return IPv4 RRset. -.PP -.nf -struct dns_query * -\fBdns_submit_a4dnsbl\fR(\fIctx\fR, - const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR, - dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_query * -\fBdns_submit_a4dnsbl_txt\fR(\fIctx\fR, - const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR, - dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_query * -\fBdns_submit_a6dnsbl\fR(\fIctx\fR, - const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR, - dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_query * -\fBdns_submit_a6dnsbl_txt\fR(\fIctx\fR, - const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR, - dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_rr_a4 *\fBdns_resolve_a4dnsbl\fR(\fIctx\fR, - const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR) -struct dns_rr_txt *\fBdns_resolve_a4dnsbl_txt\fR(\fIctx\fR, - const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR) -struct dns_rr_a4 *\fBdns_resolve_a6dnsbl\fR(\fIctx\fR, - const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR) -struct dns_rr_txt *\fBdns_resolve_a6dnsbl_txt\fR(\fIctx\fR, - const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR) -.fi -Perform (submit or resolve) a DNSBL query for the given \fIdnsbl\fR -domain and an IP \fIaddr\fR in question, requesting either A or TXT -records. - -.SS "RHSBL Interface" -.PP -RHSBL is similar to DNSBL, but instead of an IP address, the -parameter is a domain name. -.PP -.nf -struct dns_query * -\fBdns_submit_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR, - dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_query * -\fBdns_submit_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR, - dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR); -struct dns_rr_a4 * -\fBdns_resolve_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR); -struct dns_rr_txt * -\fBdns_resolve_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR); -.fi -Perform (submit or resolve) a RHSBL query for the given \fIrhsbl\fR -domain and \fIname\fR in question, requesting either A or TXT records. - - -.SH "LOW-LEVEL INTERFACE" - -.SS "Domain Names (DNs)" - -.PP -A DN is a series of domain name labels each starts with length byte, -followed by empty label (label with zero length). The following -routines to work with DNs are provided. - -.PP -.nf -unsigned \fBdns_dnlen\fR(const unsigned char *\fIdn\fR) -.fi -.RS -return length of the domain name \fIdn\fR, including the terminating label. -.RE - -.PP -.nf -unsigned \fBdns_dnlabels\fR(const unsigned char *\fIdn\fR) -.fi -.RS -return number of non-zero labels in domain name \fIdn\fR. -.RE - -.PP -.nf -unsigned \fBdns_dnequal\fR(\fIdn1\fR, \fIdn2\fR) - const unsigned char *\fIdn1\fR, *\fIdn2\fR; -.fi -.RS -test whenever the two domain names, \fIdn1\fR and \fIdn2\fR, are -equal (case-insensitive). Return domain name length if equal -or 0 if not. -.RE - -.PP -.nf -unsigned \fBdns_dntodn\fR(\fIsdn\fR, \fIddn\fR, \fIdnsiz\fR) - const unsigned char *\fIsdn\fR; - unsigned char *\fIddn\fR; - unsigned \fIdnsiz\fR; -.fi -.RS -copies the source domain name \fIsdn\fR to destination buffer \fIddn\fR -of size \fIdnsiz\fR. Return domain name length or 0 if \fIddn\fR is -too small. -.RE - -.PP -.nf -int \fBdns_ptodn\fR(\fIname\fR, \fInamelen\fR, \fIdn\fR, \fIdnsiz\fR, \fIisabs\fR) -int \fBdns_sptodn\fR(\fIname\fR, \fIdn\fR, \fIdnsiz\fR) - const char *\fIname\fR; unsigned \fInamelen\fR; - unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR; - int *\fIisabs\fR; -.fi -.RS -convert asciiz name \fIname\fR of length \fInamelen\fR to DN format, -placing result into buffer \fIdn\fR of size \fIdnsiz\fR. Return -length of the DN if successeful, 0 if the \fIdn\fR buffer supplied is -too small, or negative value if \fIname\fR is invalid. If \fIisabs\fR -is non-NULL and conversion was successeful, *\fIisabs\fR will be set to -either 1 or 0 depending whenever \fIname\fR was absolute (i.e. ending with -a dot) or not. Name length, \fInamelength\fR, may be zero, in which case -strlen(\fIname\fR) will be used. Second form, \fBdns_sptodn\fR(), is a -simplified form of \fBdns_ptodn\fR(), equivalent to -.br -.nf -\fBdns_ptodn\fR(\fIname\fR, 0, \fIdn\fR, \fIdnlen\fR, 0). -.fi -.RE - -.PP -.nf -extern const unsigned char \fBdns_inaddr_arpa_dn\fR[] -int \fBdns_a4todn\fR(const struct in_addr *\fIaddr\fR, const unsigned char *\fItdn\fR, - unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR) -int \fBdns_a4ptodn\fR(const struct in_addr *\fIaddr\fR, const char *\fItname\fR, - unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR) -extern const unsigned char \fBdns_ip6_arpa_dn\fR[] -int \fBdns_a6todn\fR(const struct in6_addr *\fIaddr\fR, const unsigned char *\fItdn\fR, - unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR) -int \fBdns_a6ptodn\fR(const struct in6_addr *\fIaddr\fR, const char *\fItname\fR, - unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR) -.fi -.RS -several variants of routines to convert IPv4 and IPv6 address \fIaddr\fR -into reverseDNS-like domain name in DN format, storing result in \fIdn\fR -of size \fIdnsiz\fR. \fItdn\fR (or \fItname\fR) is the base zone name, -like in-addr.arpa for IPv4 or in6.arpa for IPv6. If \fItdn\fR (or \fItname\fR) -is NULL, \fBdns_inaddr_arpa_dn\fR (or \fBdns_ip6_arpa_dn\fR) will be used. -The routines may be used to construct a DN for a DNSBL lookup for example. -All routines return length of the resulting DN on success, -1 if resulting -DN is invalid, or 0 if the \fIdn\fR buffer (\fIdnsiz\fR) is too small. -To hold standard rDNS DN, a buffer of size \fBDNS_A4RSIZE\fR (30 bytes) for -IPv4 address, or \fBDNS_A6RSIZE\fR (74 bytes) for IPv6 address, is sufficient. -.RE - -.PP -.nf -int \fBdns_dntop\fR(\fIdn\fR, \fIname\fR, \fInamesiz\fR) - const unsigned char *\fIdn\fR; - const char *\fIname\fR; unsigned \fInamesiz\fR; -.fi -.RS -convert domain name \fIdn\fR in DN format to asciiz string, placing result -into \fIname\fR buffer of size \fInamesiz\fR. Maximum length of asciiz -representation of domain name is \fBDNS_MAXNAME\fR (1024) bytes. Root -domain is represented as empty string. Return length of the resulting name -(including terminating character, i.e. strlen(name)+1) on success, 0 if the -\fIname\fR buffer is too small, or negative value if \fIdn\fR is invalid -(last case should never happen since all routines in this library which -produce domain names ensure the DNs generated are valid). -.RE - -.PP -.nf -const char *\fBdns_dntosp\fR(const unsigned char *\fIdn\fR) -.fi -.RS -convert domain name \fIdn\fR in DN format to asciiz string using static -buffer. Return the resulting asciiz string on success or NULL on failure. -Note since this routine uses static buffer, it is not thread-safe. -.RE - -.PP -.nf -unsigned \fBdns_dntop_size\fR(const unsigned char *\fIdn\fR) -.fi -.RS -return the buffer size needed to convert the \fIdn\fR domain name -in DN format to asciiz string, for \fBdns_dntop\fR(). The routine -return either the size of buffer required, including the trailing -zero byte, or 0 if \fIdn\fR is invalid. -.RE - -.SS "Working with DNS Packets" - -.PP -The following routines are provided to encode and decode DNS on-wire -packets. This is low-level interface. - -.PP -DNS response codes (returned by \fBdns_rcode\fR() routine) are -defined as constants prefixed with \fBDNS_R_\fR. See udns.h -header file for the complete list. In particular, constants -\fBDNS_R_NOERROR\fR (0), \fBDNS_R_SERVFAIL\fR, \fBDNS_R_NXDOMAIN\fR -may be of interest to an application. - -.PP -.nf -unsigned \fBdns_get16\fR(const unsigned char *\fIp\fR) -unsigned \fBdns_get32\fR(const unsigned char *\fIp\fR) -.fi -.RS -helper routines, convert 16-bit or 32-bit integer in on-wire -format pointed to by \fIp\fR to unsigned. -.RE - -.PP -.nf -unsigned char *\fBdns_put16\fR(unsigned char *\fId\fR, unsigned \fIn\fR) -unsigned char *\fBdns_put32\fR(unsigned char *\fId\fR, unsigned \fIn\fR) -.fi -.RS -helper routine, convert unsigned 16-bit or 32-bit integer \fIn\fR to -on-wire format to buffer pointed to by \fId\fR, return \fId\fR+2 or -\fId\fR+4. -.RE - -.PP -.nf -\fBDNS_HSIZE\fR (12) -.fi -.RS -defines size of DNS header. Data section -in the DNS packet immediately follows the header. In the header, -there are query identifier (id), various flags and codes, -and number of resource records in various data sections. -See udns.h header file for complete list of DNS header definitions. -.RE - -.PP -.nf -unsigned \fBdns_qid\fR(const unsigned char *\fIpkt\fR) -int \fBdns_rd\fR(const unsigned char *\fIpkt\fR) -int \fBdns_tc\fR(const unsigned char *\fIpkt\fR) -int \fBdns_aa\fR(const unsigned char *\fIpkt\fR) -int \fBdns_qr\fR(const unsigned char *\fIpkt\fR) -int \fBdns_ra\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_opcode\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_rcode\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_numqd\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_numan\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_numns\fR(const unsigned char *\fIpkt\fR) -unsigned \fBdns_numar\fR(const unsigned char *\fIpkt\fR) -const unsigned char *\fBdns_payload\fR(const unsigned char *\fIpkt\fR) -.fi -.RS -return various parts from the DNS packet header \fIpkt\fR: -query identifier (qid), -recursion desired (rd) flag, -truncation occured (tc) flag, -authoritative answer (aa) flag, -query response (qr) flag, -recursion available (ra) flag, -operation code (opcode), -result code (rcode), -number of entries in question section (numqd), -number of answers (numan), -number of authority records (numns), -number of additional records (numar), -and the pointer to the packet data (payload). -.RE - -.PP -.nf -int \fBdns_getdn\fR(\fIpkt\fR, \fIcurp\fR, \fIpkte\fR, \fIdn\fR, \fIdnsiz\fR) -const unsigned char *\fBdns_skipdn\fR(\fIcur\fR, \fIpkte\fR) - const unsigned char *\fIpkt\fR, *\fIpkte\fR, **\fIcurp\fR, *\fIcur\fR; - unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR; -.fi -.RS -\fBdns_getdn\fR() extract DN from DNS packet \fIpkt\fR which ends before -\fIpkte\fR starting at position *\fIcurp\fR into buffer pointed to by -\fIdn\fR of size \fIdnsiz\fR. Upon successeful completion, *\fIcurp\fR -will point to the next byte in the packet after the extracted domain name. -It return positive number (length of the DN if \fIdn\fR) upon successeful -completion, negative value on error (when the packet contains invalid data), -or zero if the \fIdnsiz\fR is too small (maximum length of a domain name is -\fBDNS_MAXDN\fR). \fBdns_skipdn\fR() return pointer to the next byte in -DNS packet which ends up before \fIpkte\fR after a domain name which starts -at the \fIcur\fP byte, or NULL if the packet is invalid. \fBdns_skipdn\fR() -is more or less equivalent to what \fBdns_getdn\fR() does, except it does not -actually extract the domain name in question, and uses simpler interface. -.RE - -.PP -.nf -struct \fBdns_rr\fR { - unsigned char \fBdnsrr_dn\fR[DNS_MAXDN]; /* the RR DN name */ - enum dns_class \fBdnsrr_cls\fR; /* class of the RR */ - enum dns_type \fBdnsrr_typ\fR; /* type of the RR */ - unsigned \fBdnsrr_ttl\fR; /* TTL value */ - unsigned \fBdnsrr_dsz\fR; /* size of data in bytes */ - const unsigned char *\fBdnsrr_dptr\fR; /* pointer to the first data byte */ - const unsigned char *\fBdnsrr_dend\fR; /* next byte after RR */ -}; -.fi -.RS -The \fBdns_rr\fR structure is used to hold information about -single DNS Resource Record (RR) in an easy to use form. -.RE - -.PP -.nf -struct \fBdns_parse\fR { - const unsigned char *\fBdnsp_pkt\fR; /* pointer to the packet being parsed */ - const unsigned char *\fBdnsp_end\fR; /* end of the packet pointer */ - const unsigned char *\fBdnsp_cur\fR; /* current packet positionn */ - const unsigned char *\fBdnsp_ans\fR; /* pointer to the answer section */ - int \fBdnsp_rrl\fR; /* number of RRs left */ - int \fBdnsp_nrr\fR; /* number of relevant RRs seen so far */ - unsigned \fBdnsp_ttl\fR; /* TTL value so far */ - const unsigned char *\fBdnsp_qdn\fR; /* the domain of interest or NULL */ - enum dns_class \fBdnsp_qcls\fR; /* class of interest or 0 for any */ - enum dns_type \fBdnsp_qtyp\fR; /* type of interest or 0 for any */ - unsigned char \fBdnsp_dnbuf\fR[DNS_MAXDN]; /* domain name buffer */ -}; -.fi -.RS -The \fBdns_parse\fR structure is used to parse DNS reply packet. -It holds information about the packet being parsed (dnsp_pkt, dnsp_end and -dnsp_cur fields), number of RRs in the current section left to do, and -the information about specific RR which we're looking for (dnsp_qdn, -dnsp_qcls and dnsp_qtyp fields). -.RE - -.PP -.nf -int \fBdns_initparse\fR(struct dns_parse *\fIp\fR, - const unsigned char *\fIqdn\fR, - const unsigned char *\fIpkt\fR, - const unsigned char *\fIcur\fR, - const unsigned char *\fIend\fR) -.fi -.RS -initializes the RR parsing structure \fIp\fR. Arguments \fIpkt\fR, \fIcur\fR -and \fIend\fR should describe the received packet: \fIpkt\fR is the start of -the packet, \fIend\fR points to the next byte after the end of the packet, -and \fIcur\fR points past the query DN in query section (to query class+type -information). And \fIqdn\fR points to the query DN. This is the arguments -passed to \fBdns_parse_fn\fR() routine. \fBdns_initparse\fR() initializes -\fBdnsp_pkt\fR, \fBdnsp_end\fR and \fBdnsp_qdn\fR fields to the corresponding -arguments, extracts and initializes \fBdnsp_qcls\fR and \fBdnsp_qtyp\fR -fields to the values found at \fIcur\fR pointer, initializes -\fBdnsp_cur\fR and \fBdnsp_ans\fR fields to be \fIcur\fR+4 (to the start of -answer section), and initializes \fBdnsp_rrl\fR field to be number of entries -in answer section. \fBdnsp_ttl\fR will be set to max TTL value, 0xffffffff, -and \fBdnsp_nrr\fR to 0. -.RE - -.PP -.nf -int \fBdns_nextrr\fR(struct dns_parse *\fIp\fR, struct dns_rr *\fIrr\fR); -.fi -.RS -searches for next RR in the packet based on the criteria provided in -the \fIp\fR structure, filling in the \fIrr\fR structure and -advancing \fIp\fR->\fBdnsp_cur\fR to the next RR in the packet. -RR selection is based on dnsp_qdn, dnsp_qcls and dnsp_qtyp fields in -the dns_parse structure. Any (or all) of the 3 fields may be 0, -which means any actual value from the packet is acceptable. In case -the field isn't 0 (or NULL for dnsp_qdn), only RRs with corresponding -characteristics are acceptable. Additionally, when dnsp_qdn is non-NULL, -\fBdns_nextrr\fR() performs automatic CNAME expansion. -Routine will return positive value on success, 0 in case it reached the end -of current section in the packet (\fIp\fR->\fBdnsp_rrl\fR is zero), or -negative value if next RR can not be decoded (packet format is invalid). -The routine updates \fIp\fR->\fBdnsp_qdn\fR automatically when this -field is non-NULL and it encounters appropriate CNAME RRs (saving CNAME -target in \fIp\fR->\fBdnsp_dnbuf\fR), so after end of the process, -\fIp\fR->\fBdnsp_qdn\fR will point to canonical name of the domain -in question. The routine updates \fIp\fR->\fBdnsp_ttl\fR value to -be the minimum TTL of all RRs found. -.RE - -.PP -.nf -void \fBdns_rewind\fR(struct dns_parse *\fIp\fR, const unsigned char *\fIqdn\fR) -.fi -.RS -this routine "rewinds" the packet parse state structure to be at the -same state as after a call to \fBdns_initparse\fR(), i.e. reposition -the parse structure \fIp\fR to the start of answer section and -initialize \fIp\fR->\fBdnsp_rrl\fR to the number of entries in -answer section. -.RE - -.PP -.nf -int \fBdns_stdrr_size\fR(const struct dns_parse *\fIp\fR); -.fi -.RS -return size to hold standard RRset structure information, as shown -in \fBdns_rr_null\fR structure (for the query and canonical -names). Used to calculate amount of memory to allocate for common -part of type-specific RR structures in parsing routines. -.RE - -.PP -.nf -void *\fBdns_stdrr_finish\fR(struct dns_rr_null *\fIret\fR, char *\fIcp\fR, - const struct dns_parse *\fIp\fR); -.fi -.RS -initializes standard RRset fields in \fIret\fR structure using buffer -pointed to by \fIcp\fR, which should have at least as many bytes -as \fBdns_stdrr_size\fR(\fIp\fR) returned. Used to finalize common -part of type-specific RR structures in parsing routines. -.RE - -.PP -See library source for usage examples of all the above low-level routines, -especially source of the parsing routines. - -.SS "Auxilary Routines" - -.PP -.nf -int \fBdns_pton\fR(int \fIaf\fR, const char *\fIsrc\fR, void *\fIdst\fR); -.fi -.RS -privides functionality similar to standard \fBinet_pton\fR() routine, -to convert printable representation of an IP address of family \fIaf\fR -(either \fBAF_INET\fR or \fBAF_INET6\fR) pointed to by \fIsrc\fR into -binary form suitable for socket addresses and transmission over network, -in buffer pointed to by \fIdst\fR. The destination buffer should be -of size 4 for \fBAF_INET\fR family or 16 for \fBAF_INET6\fR. -The return value is positive on success, 0 if \fIsrc\fR is not a valid text -representation of an address of family \fIaf\fR, or negative if the -given address family is not supported. -.RE - -.PP -.nf -const char *\fBdns_ntop\fR(int \fIaf\fR, const void *\fIsrc\fR, - char *\fIdst\fR, int \fIdstsize\fR) -.fi -.RS -privides functionality similar to standard \fBinet_ntop\fR() routine, -to convert binary representation of an IP address of family \fIaf\fR -(either \fBAF_INET\fR or \fBAF_INET6\fR) pointed to by \fIsrc\fR -(either 4 or 16 bytes) into printable form in buffer in buffer pointed -to by \fIdst\fR of size \fIdstsize\fR. The destination buffer should be -at least of size 16 bytes for \fBAF_INET\fR family or 46 bytes for -\fBAF_INET6\fR. The return value is either \fIdst\fR, or NULL pointer -if \fIdstsize\fR is too small to hold this address or if the given -address family is not supported. -.RE - -.SH AUTHOR -.PP -The \fBudns\fR library has been written by Michael Tokarev, mjt@corpit.ru. - -.SH VERSION -.PP -This manual page corresponds to udns version 0.0.9, released Jan-2007. diff --git a/deps/udns/udns.h b/deps/udns/udns.h deleted file mode 100644 index 1186bb22fb0..00000000000 --- a/deps/udns/udns.h +++ /dev/null @@ -1,745 +0,0 @@ -/* $Id: udns.h,v 1.51 2007/01/15 21:19:08 mjt Exp $ - header file for the UDNS library. - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifndef UDNS_VERSION /* include guard */ - -#define UDNS_VERSION "0.0.9" - -#ifdef WINDOWS -# ifdef UDNS_DYNAMIC_LIBRARY -# ifdef DNS_LIBRARY_BUILD -# define UDNS_API __declspec(dllexport) -# define UDNS_DATA_API __declspec(dllexport) -# else -# define UDNS_API __declspec(dllimport) -# define UDNS_DATA_API __declspec(dllimport) -# endif -# endif -#endif - -#ifndef UDNS_API -# define UDNS_API -#endif -#ifndef UDNS_DATA_API -# define UDNS_DATA_API -#endif - -#include /* for time_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* forward declarations if sockets stuff isn't #include'd */ -struct in_addr; -struct in6_addr; -struct sockaddr; - -/**************************************************************************/ -/**************** Common definitions **************************************/ - -UDNS_API const char * -dns_version(void); - -struct dns_ctx; -struct dns_query; - -/* shorthand for [const] unsigned char */ -typedef unsigned char dnsc_t; -typedef const unsigned char dnscc_t; - -#define DNS_MAXDN 255 /* max DN length */ -#define DNS_DNPAD 1 /* padding for DN buffers */ -#define DNS_MAXLABEL 63 /* max DN label length */ -#define DNS_MAXNAME 1024 /* max asciiz domain name length */ -#define DNS_HSIZE 12 /* DNS packet header size */ -#define DNS_PORT 53 /* default domain port */ -#define DNS_MAXSERV 6 /* max servers to consult */ -#define DNS_MAXPACKET 512 /* max traditional-DNS UDP packet size */ -#define DNS_EDNS0PACKET 4096 /* EDNS0 packet size to use */ - -enum dns_class { /* DNS RR Classes */ - DNS_C_INVALID = 0, /* invalid class */ - DNS_C_IN = 1, /* Internet */ - DNS_C_CH = 3, /* CHAOS */ - DNS_C_HS = 4, /* HESIOD */ - DNS_C_ANY = 255 /* wildcard */ -}; - -enum dns_type { /* DNS RR Types */ - DNS_T_INVALID = 0, /* Cookie. */ - DNS_T_A = 1, /* Host address. */ - DNS_T_NS = 2, /* Authoritative server. */ - DNS_T_MD = 3, /* Mail destination. */ - DNS_T_MF = 4, /* Mail forwarder. */ - DNS_T_CNAME = 5, /* Canonical name. */ - DNS_T_SOA = 6, /* Start of authority zone. */ - DNS_T_MB = 7, /* Mailbox domain name. */ - DNS_T_MG = 8, /* Mail group member. */ - DNS_T_MR = 9, /* Mail rename name. */ - DNS_T_NULL = 10, /* Null resource record. */ - DNS_T_WKS = 11, /* Well known service. */ - DNS_T_PTR = 12, /* Domain name pointer. */ - DNS_T_HINFO = 13, /* Host information. */ - DNS_T_MINFO = 14, /* Mailbox information. */ - DNS_T_MX = 15, /* Mail routing information. */ - DNS_T_TXT = 16, /* Text strings. */ - DNS_T_RP = 17, /* Responsible person. */ - DNS_T_AFSDB = 18, /* AFS cell database. */ - DNS_T_X25 = 19, /* X_25 calling address. */ - DNS_T_ISDN = 20, /* ISDN calling address. */ - DNS_T_RT = 21, /* Router. */ - DNS_T_NSAP = 22, /* NSAP address. */ - DNS_T_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */ - DNS_T_SIG = 24, /* Security signature. */ - DNS_T_KEY = 25, /* Security key. */ - DNS_T_PX = 26, /* X.400 mail mapping. */ - DNS_T_GPOS = 27, /* Geographical position (withdrawn). */ - DNS_T_AAAA = 28, /* Ip6 Address. */ - DNS_T_LOC = 29, /* Location Information. */ - DNS_T_NXT = 30, /* Next domain (security). */ - DNS_T_EID = 31, /* Endpoint identifier. */ - DNS_T_NIMLOC = 32, /* Nimrod Locator. */ - DNS_T_SRV = 33, /* Server Selection. */ - DNS_T_ATMA = 34, /* ATM Address */ - DNS_T_NAPTR = 35, /* Naming Authority PoinTeR */ - DNS_T_KX = 36, /* Key Exchange */ - DNS_T_CERT = 37, /* Certification record */ - DNS_T_A6 = 38, /* IPv6 address (deprecates AAAA) */ - DNS_T_DNAME = 39, /* Non-terminal DNAME (for IPv6) */ - DNS_T_SINK = 40, /* Kitchen sink (experimentatl) */ - DNS_T_OPT = 41, /* EDNS0 option (meta-RR) */ - DNS_T_DS = 43, /* DNSSEC */ - DNS_T_NSEC = 47, /* DNSSEC */ - DNS_T_TSIG = 250, /* Transaction signature. */ - DNS_T_IXFR = 251, /* Incremental zone transfer. */ - DNS_T_AXFR = 252, /* Transfer zone of authority. */ - DNS_T_MAILB = 253, /* Transfer mailbox records. */ - DNS_T_MAILA = 254, /* Transfer mail agent records. */ - DNS_T_ANY = 255, /* Wildcard match. */ - DNS_T_ZXFR = 256, /* BIND-specific, nonstandard. */ - DNS_T_MAX = 65536 -}; - -/**************************************************************************/ -/**************** Domain Names (DNs) **************************************/ - -/* return length of the DN */ -UDNS_API unsigned -dns_dnlen(dnscc_t *dn); - -/* return #of labels in a DN */ -UDNS_API unsigned -dns_dnlabels(dnscc_t *dn); - -/* lower- and uppercase single DN char */ -#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c)) -#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) - -/* compare the DNs, return dnlen of equal or 0 if not */ -UDNS_API unsigned -dns_dnequal(dnscc_t *dn1, dnscc_t *dn2); - -/* copy one DN to another, size checking */ -UDNS_API unsigned -dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz); - -/* convert asciiz string of length namelen (0 to use strlen) to DN */ -UDNS_API int -dns_ptodn(const char *name, unsigned namelen, - dnsc_t *dn, unsigned dnsiz, int *isabs); - -/* simpler form of dns_ptodn() */ -#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0) - -UDNS_DATA_API extern dnscc_t dns_inaddr_arpa_dn[14]; -#define DNS_A4RSIZE 30 -UDNS_API int -dns_a4todn(const struct in_addr *addr, dnscc_t *tdn, - dnsc_t *dn, unsigned dnsiz); -UDNS_API int -dns_a4ptodn(const struct in_addr *addr, const char *tname, - dnsc_t *dn, unsigned dnsiz); -UDNS_API dnsc_t * -dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne); - -UDNS_DATA_API extern dnscc_t dns_ip6_arpa_dn[10]; -#define DNS_A6RSIZE 74 -UDNS_API int -dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn, - dnsc_t *dn, unsigned dnsiz); -UDNS_API int -dns_a6ptodn(const struct in6_addr *addr, const char *tname, - dnsc_t *dn, unsigned dnsiz); -UDNS_API dnsc_t * -dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne); - -/* convert DN into asciiz string */ -UDNS_API int -dns_dntop(dnscc_t *dn, char *name, unsigned namesiz); - -/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */ -UDNS_API const char * -dns_dntosp(dnscc_t *dn); - -/* return buffer size (incl. null byte) required for asciiz form of a DN */ -UDNS_API unsigned -dns_dntop_size(dnscc_t *dn); - -/* either wrappers or reimplementations for inet_ntop() and inet_pton() */ -UDNS_API const char *dns_ntop(int af, const void *src, char *dst, int size); -UDNS_API int dns_pton(int af, const char *src, void *dst); - -/**************************************************************************/ -/**************** DNS raw packet layout ***********************************/ - -enum dns_rcode { /* reply codes */ - DNS_R_NOERROR = 0, /* ok, no error */ - DNS_R_FORMERR = 1, /* format error */ - DNS_R_SERVFAIL = 2, /* server failed */ - DNS_R_NXDOMAIN = 3, /* domain does not exists */ - DNS_R_NOTIMPL = 4, /* not implemented */ - DNS_R_REFUSED = 5, /* query refused */ - /* these are for BIND_UPDATE */ - DNS_R_YXDOMAIN = 6, /* Name exists */ - DNS_R_YXRRSET = 7, /* RRset exists */ - DNS_R_NXRRSET = 8, /* RRset does not exist */ - DNS_R_NOTAUTH = 9, /* Not authoritative for zone */ - DNS_R_NOTZONE = 10, /* Zone of record different from zone section */ - /*ns_r_max = 11,*/ - /* The following are TSIG extended errors */ - DNS_R_BADSIG = 16, - DNS_R_BADKEY = 17, - DNS_R_BADTIME = 18 -}; - -static __inline unsigned dns_get16(dnscc_t *s) { - return ((unsigned)s[0]<<8) | s[1]; -} -static __inline unsigned dns_get32(dnscc_t *s) { - return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16) - | ((unsigned)s[2]<<8) | s[3]; -} -static __inline dnsc_t *dns_put16(dnsc_t *d, unsigned n) { - *d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); return d; -} -static __inline dnsc_t *dns_put32(dnsc_t *d, unsigned n) { - *d++ = (dnsc_t)((n >> 24) & 255); *d++ = (dnsc_t)((n >> 16) & 255); - *d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); - return d; -} - -/* return pseudo-random 16bits number */ -UDNS_API unsigned dns_random16(void); - -/* DNS Header layout */ -enum { - /* bytes 0:1 - query ID */ - DNS_H_QID1 = 0, - DNS_H_QID2 = 1, - DNS_H_QID = DNS_H_QID1, -#define dns_qid(pkt) dns_get16((pkt)+DNS_H_QID) - /* byte 2: flags1 */ - DNS_H_F1 = 2, - DNS_HF1_QR = 0x80, /* query response flag */ -#define dns_qr(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_QR) - DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */ -#define dns_opcode(pkt) (((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3) - DNS_HF1_AA = 0x04, /* auth answer */ -#define dns_aa(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_AA) - DNS_HF1_TC = 0x02, /* truncation flag */ -#define dns_tc(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_TC) - DNS_HF1_RD = 0x01, /* recursion desired (may be set in query) */ -#define dns_rd(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_RD) - /* byte 3: flags2 */ - DNS_H_F2 = 3, - DNS_HF2_RA = 0x80, /* recursion available */ -#define dns_ra(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RA) - DNS_HF2_Z = 0x70, /* reserved */ - DNS_HF2_RCODE = 0x0f, /* response code, DNS_R_XXX above */ -#define dns_rcode(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RCODE) - /* bytes 4:5: qdcount, numqueries */ - DNS_H_QDCNT1 = 4, - DNS_H_QDCNT2 = 5, - DNS_H_QDCNT = DNS_H_QDCNT1, -#define dns_numqd(pkt) dns_get16((pkt)+4) - /* bytes 6:7: ancount, numanswers */ - DNS_H_ANCNT1 = 6, - DNS_H_ANCNT2 = 7, - DNS_H_ANCNT = DNS_H_ANCNT1, -#define dns_numan(pkt) dns_get16((pkt)+6) - /* bytes 8:9: nscount, numauthority */ - DNS_H_NSCNT1 = 8, - DNS_H_NSCNT2 = 9, - DNS_H_NSCNT = DNS_H_NSCNT1, -#define dns_numns(pkt) dns_get16((pkt)+8) - /* bytes 10:11: arcount, numadditional */ - DNS_H_ARCNT1 = 10, - DNS_H_ARCNT2 = 11, - DNS_H_ARCNT = DNS_H_ARCNT1, -#define dns_numar(pkt) dns_get16((pkt)+10) -#define dns_payload(pkt) ((pkt)+DNS_HSIZE) -}; - -/* packet buffer: start at pkt, end before pkte, current pos *curp. - * extract a DN and set *curp to the next byte after DN in packet. - * return -1 on error, 0 if dnsiz is too small, or dnlen on ok. - */ -UDNS_API int -dns_getdn(dnscc_t *pkt, dnscc_t **curp, dnscc_t *end, - dnsc_t *dn, unsigned dnsiz); - -/* skip the DN at position cur in packet ending before pkte, - * return pointer to the next byte after the DN or NULL on error */ -UDNS_API dnscc_t * -dns_skipdn(dnscc_t *end, dnscc_t *cur); - -struct dns_rr { /* DNS Resource Record */ - dnsc_t dnsrr_dn[DNS_MAXDN]; /* the DN of the RR */ - enum dns_class dnsrr_cls; /* Class */ - enum dns_type dnsrr_typ; /* Type */ - unsigned dnsrr_ttl; /* Time-To-Live (TTL) */ - unsigned dnsrr_dsz; /* data size */ - dnscc_t *dnsrr_dptr; /* pointer to start of data */ - dnscc_t *dnsrr_dend; /* past end of data */ -}; - -struct dns_parse { /* RR/packet parsing state */ - dnscc_t *dnsp_pkt; /* start of the packet */ - dnscc_t *dnsp_end; /* end of the packet */ - dnscc_t *dnsp_cur; /* current packet position */ - dnscc_t *dnsp_ans; /* start of answer section */ - int dnsp_rrl; /* number of RRs left to go */ - int dnsp_nrr; /* RR count so far */ - unsigned dnsp_ttl; /* TTL value so far */ - dnscc_t *dnsp_qdn; /* the RR DN we're looking for */ - enum dns_class dnsp_qcls; /* RR class we're looking for or 0 */ - enum dns_type dnsp_qtyp; /* RR type we're looking for or 0 */ - dnsc_t dnsp_dnbuf[DNS_MAXDN]; /* domain buffer */ -}; - -/* initialize the parse structure */ -UDNS_API void -dns_initparse(struct dns_parse *p, dnscc_t *qdn, - dnscc_t *pkt, dnscc_t *cur, dnscc_t *end); - -/* search next RR, <0=error, 0=no more RRs, >0 = found. */ -UDNS_API int -dns_nextrr(struct dns_parse *p, struct dns_rr *rr); - -UDNS_API void -dns_rewind(struct dns_parse *p, dnscc_t *qdn); - - -/**************************************************************************/ -/**************** Resolver Context ****************************************/ - -/* default resolver context */ -UDNS_DATA_API extern struct dns_ctx dns_defctx; - -/* reset resolver context to default state, close it if open, drop queries */ -UDNS_API void -dns_reset(struct dns_ctx *ctx); - -/* reset resolver context and read in system configuration */ -UDNS_API int -dns_init(struct dns_ctx *ctx, int do_open); - -/* return new resolver context with the same settings as copy */ -UDNS_API struct dns_ctx * -dns_new(const struct dns_ctx *copy); - -/* free resolver context returned by dns_new(); all queries are dropped */ -UDNS_API void -dns_free(struct dns_ctx *ctx); - -/* add nameserver for a resolver context (or reset nslist if serv==NULL) */ -UDNS_API int -dns_add_serv(struct dns_ctx *ctx, const char *serv); - -/* add nameserver using struct sockaddr structure (with ports) */ -UDNS_API int -dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa); - -/* add search list element for a resolver context (or reset it if srch==NULL) */ -UDNS_API int -dns_add_srch(struct dns_ctx *ctx, const char *srch); - -/* set options for a resolver context */ -UDNS_API int -dns_set_opts(struct dns_ctx *ctx, const char *opts); - -enum dns_opt { /* options */ - DNS_OPT_FLAGS, /* flags, DNS_F_XXX */ - DNS_OPT_TIMEOUT, /* timeout in secounds */ - DNS_OPT_NTRIES, /* number of retries */ - DNS_OPT_NDOTS, /* ndots */ - DNS_OPT_UDPSIZE, /* EDNS0 UDP size */ - DNS_OPT_PORT, /* port to use */ -}; - -/* set or get (if val<0) an option */ -UDNS_API int -dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val); - -enum dns_flags { - DNS_NOSRCH = 0x00010000, /* do not perform search */ - DNS_NORD = 0x00020000, /* request no recursion */ - DNS_AAONLY = 0x00040000, /* set AA flag in queries */ -}; - -/* set the debug function pointer */ -typedef void -(dns_dbgfn)(int code, const struct sockaddr *sa, unsigned salen, - dnscc_t *pkt, int plen, - const struct dns_query *q, void *data); -UDNS_API void -dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn); - -/* open and return UDP socket */ -UDNS_API int -dns_open(struct dns_ctx *ctx); - -/* return UDP socket or -1 if not open */ -UDNS_API int -dns_sock(const struct dns_ctx *ctx); - -/* close the UDP socket */ -UDNS_API void -dns_close(struct dns_ctx *ctx); - -/* return number of requests queued */ -UDNS_API int -dns_active(const struct dns_ctx *ctx); - -/* return status of the last operation */ -UDNS_API int -dns_status(const struct dns_ctx *ctx); -UDNS_API void -dns_setstatus(struct dns_ctx *ctx, int status); - -/* handle I/O event on UDP socket */ -UDNS_API void -dns_ioevent(struct dns_ctx *ctx, time_t now); - -/* process any timeouts, return time in secounds to the - * next timeout (or -1 if none) but not greather than maxwait */ -UDNS_API int -dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now); - -/* define timer requesting routine to use */ -typedef void dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data); -UDNS_API void -dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data); - -/**************************************************************************/ -/**************** Making Queries ******************************************/ - -/* query callback routine */ -typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data); - -/* query parse routine: raw DNS => application structure */ -typedef int -dns_parse_fn(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **res); - -enum dns_status { - DNS_E_NOERROR = 0, /* ok, not an error */ - DNS_E_TEMPFAIL = -1, /* timeout, SERVFAIL or similar */ - DNS_E_PROTOCOL = -2, /* got garbled reply */ - DNS_E_NXDOMAIN = -3, /* domain does not exists */ - DNS_E_NODATA = -4, /* domain exists but no data of reqd type */ - DNS_E_NOMEM = -5, /* out of memory while processing */ - DNS_E_BADQUERY = -6 /* the query is malformed */ -}; - -/* submit generic DN query */ -UDNS_API struct dns_query * -dns_submit_dn(struct dns_ctx *ctx, - dnscc_t *dn, int qcls, int qtyp, int flags, - dns_parse_fn *parse, dns_query_fn *cbck, void *data); -/* submit generic name query */ -UDNS_API struct dns_query * -dns_submit_p(struct dns_ctx *ctx, - const char *name, int qcls, int qtyp, int flags, - dns_parse_fn *parse, dns_query_fn *cbck, void *data); - -/* cancel the given async query in progress */ -UDNS_API int -dns_cancel(struct dns_ctx *ctx, struct dns_query *q); - -/* resolve a generic query, return the answer */ -UDNS_API void * -dns_resolve_dn(struct dns_ctx *ctx, - dnscc_t *qdn, int qcls, int qtyp, int flags, - dns_parse_fn *parse); -UDNS_API void * -dns_resolve_p(struct dns_ctx *ctx, - const char *qname, int qcls, int qtyp, int flags, - dns_parse_fn *parse); -UDNS_API void * -dns_resolve(struct dns_ctx *ctx, struct dns_query *q); - - -/* Specific RR handlers */ - -#define dns_rr_common(prefix) \ - char *prefix##_cname; /* canonical name */ \ - char *prefix##_qname; /* original query name */ \ - unsigned prefix##_ttl; /* TTL value */ \ - int prefix##_nrr /* number of records */ - -struct dns_rr_null { /* NULL RRset, aka RRset template */ - dns_rr_common(dnsn); -}; - -UDNS_API int -dns_stdrr_size(const struct dns_parse *p); -UDNS_API void * -dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p); - -struct dns_rr_a4 { /* the A RRset */ - dns_rr_common(dnsa4); - struct in_addr *dnsa4_addr; /* array of addresses, naddr elements */ -}; - -UDNS_API dns_parse_fn dns_parse_a4; /* A RR parsing routine */ -typedef void /* A query callback routine */ -dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data); - -/* submit A IN query */ -UDNS_API struct dns_query * -dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags, - dns_query_a4_fn *cbck, void *data); - -/* resolve A IN query */ -UDNS_API struct dns_rr_a4 * -dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags); - - -struct dns_rr_a6 { /* the AAAA RRset */ - dns_rr_common(dnsa6); - struct in6_addr *dnsa6_addr; /* array of addresses, naddr elements */ -}; - -UDNS_API dns_parse_fn dns_parse_a6; /* A RR parsing routine */ -typedef void /* A query callback routine */ -dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data); - -/* submit AAAA IN query */ -UDNS_API struct dns_query * -dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags, - dns_query_a6_fn *cbck, void *data); - -/* resolve AAAA IN query */ -UDNS_API struct dns_rr_a6 * -dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags); - - -struct dns_rr_ptr { /* the PTR RRset */ - dns_rr_common(dnsptr); - char **dnsptr_ptr; /* array of PTRs */ -}; - -UDNS_API dns_parse_fn dns_parse_ptr; /* PTR RR parsing routine */ -typedef void /* PTR query callback */ -dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data); -/* submit PTR IN in-addr.arpa query */ -UDNS_API struct dns_query * -dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr, - dns_query_ptr_fn *cbck, void *data); -/* resolve PTR IN in-addr.arpa query */ -UDNS_API struct dns_rr_ptr * -dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr); - -/* the same as above, but for ip6.arpa */ -UDNS_API struct dns_query * -dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr, - dns_query_ptr_fn *cbck, void *data); -UDNS_API struct dns_rr_ptr * -dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr); - - -struct dns_mx { /* single MX RR */ - int priority; /* MX priority */ - char *name; /* MX name */ -}; -struct dns_rr_mx { /* the MX RRset */ - dns_rr_common(dnsmx); - struct dns_mx *dnsmx_mx; /* array of MXes */ -}; -UDNS_API dns_parse_fn dns_parse_mx; /* MX RR parsing routine */ -typedef void /* MX RR callback */ -dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data); -/* submit MX IN query */ -UDNS_API struct dns_query * -dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags, - dns_query_mx_fn *cbck, void *data); -/* resolve MX IN query */ -UDNS_API struct dns_rr_mx * -dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags); - - -struct dns_txt { /* single TXT record */ - int len; /* length of the text */ - dnsc_t *txt; /* pointer to text buffer. May contain nulls. */ -}; -struct dns_rr_txt { /* the TXT RRset */ - dns_rr_common(dnstxt); - struct dns_txt *dnstxt_txt; /* array of TXT records */ -}; -UDNS_API dns_parse_fn dns_parse_txt; /* TXT RR parsing routine */ -typedef void /* TXT RR callback */ -dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data); -/* submit TXT query */ -UDNS_API struct dns_query * -dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags, - dns_query_txt_fn *cbck, void *data); -/* resolve TXT query */ -UDNS_API struct dns_rr_txt * -dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags); - - -struct dns_srv { /* single SRV RR */ - int priority; /* SRV priority */ - int weight; /* SRV weight */ - int port; /* SRV port */ - char *name; /* SRV name */ -}; -struct dns_rr_srv { /* the SRV RRset */ - dns_rr_common(dnssrv); - struct dns_srv *dnssrv_srv; /* array of SRVes */ -}; -UDNS_API dns_parse_fn dns_parse_srv; /* SRV RR parsing routine */ -typedef void /* SRV RR callback */ -dns_query_srv_fn(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data); -/* submit SRV IN query */ -UDNS_API struct dns_query * -dns_submit_srv(struct dns_ctx *ctx, - const char *name, const char *srv, const char *proto, - int flags, dns_query_srv_fn *cbck, void *data); -/* resolve SRV IN query */ -UDNS_API struct dns_rr_srv * -dns_resolve_srv(struct dns_ctx *ctx, - const char *name, const char *srv, const char *proto, - int flags); - -/* NAPTR (RFC3403) RR type */ -struct dns_naptr { /* single NAPTR RR */ - int order; /* NAPTR order */ - int preference; /* NAPTR preference */ - char *flags; /* NAPTR flags */ - char *service; /* NAPTR service */ - char *regexp; /* NAPTR regexp */ - char *replacement; /* NAPTR replacement */ -}; - -struct dns_rr_naptr { /* the NAPTR RRset */ - dns_rr_common(dnsnaptr); - struct dns_naptr *dnsnaptr_naptr; /* array of NAPTRes */ -}; -UDNS_API dns_parse_fn dns_parse_naptr; /* NAPTR RR parsing routine */ -typedef void /* NAPTR RR callback */ -dns_query_naptr_fn(struct dns_ctx *ctx, - struct dns_rr_naptr *result, void *data); -/* submit NAPTR IN query */ -UDNS_API struct dns_query * -dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags, - dns_query_naptr_fn *cbck, void *data); -/* resolve NAPTR IN query */ -UDNS_API struct dns_rr_naptr * -dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags); - - -UDNS_API struct dns_query * -dns_submit_a4dnsbl(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl, - dns_query_a4_fn *cbck, void *data); -UDNS_API struct dns_query * -dns_submit_a4dnsbl_txt(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl, - dns_query_txt_fn *cbck, void *data); -UDNS_API struct dns_rr_a4 * -dns_resolve_a4dnsbl(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl); -UDNS_API struct dns_rr_txt * -dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl); - -UDNS_API struct dns_query * -dns_submit_a6dnsbl(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl, - dns_query_a4_fn *cbck, void *data); -UDNS_API struct dns_query * -dns_submit_a6dnsbl_txt(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl, - dns_query_txt_fn *cbck, void *data); -UDNS_API struct dns_rr_a4 * -dns_resolve_a6dnsbl(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl); -UDNS_API struct dns_rr_txt * -dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl); - -UDNS_API struct dns_query * -dns_submit_rhsbl(struct dns_ctx *ctx, - const char *name, const char *rhsbl, - dns_query_a4_fn *cbck, void *data); -UDNS_API struct dns_query * -dns_submit_rhsbl_txt(struct dns_ctx *ctx, - const char *name, const char *rhsbl, - dns_query_txt_fn *cbck, void *data); -UDNS_API struct dns_rr_a4 * -dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl); -UDNS_API struct dns_rr_txt * -dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl); - -/**************************************************************************/ -/**************** Names, Names ********************************************/ - -struct dns_nameval { - int val; - const char *name; -}; - -UDNS_DATA_API extern const struct dns_nameval dns_classtab[]; -UDNS_DATA_API extern const struct dns_nameval dns_typetab[]; -UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[]; -UDNS_API int -dns_findname(const struct dns_nameval *nv, const char *name); -#define dns_findclassname(cls) dns_findname(dns_classtab, (cls)) -#define dns_findtypename(type) dns_findname(dns_typetab, (type)) -#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode)) - -UDNS_API const char *dns_classname(enum dns_class cls); -UDNS_API const char *dns_typename(enum dns_type type); -UDNS_API const char *dns_rcodename(enum dns_rcode rcode); -const char *_dns_format_code(char *buf, const char *prefix, int code); - -UDNS_API const char *dns_strerror(int errnum); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* include guard */ diff --git a/deps/udns/udns_XtoX.c b/deps/udns/udns_XtoX.c deleted file mode 100644 index cfb6af42c08..00000000000 --- a/deps/udns/udns_XtoX.c +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id: udns_XtoX.c,v 1.1 2007/01/07 22:20:39 mjt Exp $ - udns_ntop() and udns_pton() routines, which are either - - wrappers for inet_ntop() and inet_pton() or - - reimplementations of those routines. - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "udns.h" - -#ifdef HAVE_INET_PTON_NTOP - -#include -#include -#include - -const char *dns_ntop(int af, const void *src, char *dst, int size) { - return inet_ntop(af, src, dst, size); -} - -int dns_pton(int af, const char *src, void *dst) { - return inet_pton(af, src, dst); -} - -#else - -#define inet_XtoX_prefix udns_ -#include "inet_XtoX.c" - -#endif diff --git a/deps/udns/udns_bl.c b/deps/udns/udns_bl.c deleted file mode 100644 index dc6f53b1647..00000000000 --- a/deps/udns/udns_bl.c +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id: udns_bl.c,v 1.10 2005/09/12 10:55:21 mjt Exp $ - DNSBL stuff - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include "udns.h" -#ifndef NULL -# define NULL 0 -#endif - -struct dns_query * -dns_submit_a4dnsbl(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl, - dns_query_a4_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, - dns_parse_a4, (dns_query_fn*)cbck, data); -} - -struct dns_query * -dns_submit_a4dnsbl_txt(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl, - dns_query_txt_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, - dns_parse_txt, (dns_query_fn*)cbck, data); -} - -struct dns_rr_a4 * -dns_resolve_a4dnsbl(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl) { - return (struct dns_rr_a4 *) - dns_resolve(ctx, dns_submit_a4dnsbl(ctx, addr, dnsbl, 0, 0)); -} - -struct dns_rr_txt * -dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx, - const struct in_addr *addr, const char *dnsbl) { - return (struct dns_rr_txt *) - dns_resolve(ctx, dns_submit_a4dnsbl_txt(ctx, addr, dnsbl, 0, 0)); -} - - -struct dns_query * -dns_submit_a6dnsbl(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl, - dns_query_a4_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, - dns_parse_a4, (dns_query_fn*)cbck, data); -} - -struct dns_query * -dns_submit_a6dnsbl_txt(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl, - dns_query_txt_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, - dns_parse_txt, (dns_query_fn*)cbck, data); -} - -struct dns_rr_a4 * -dns_resolve_a6dnsbl(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl) { - return (struct dns_rr_a4 *) - dns_resolve(ctx, dns_submit_a6dnsbl(ctx, addr, dnsbl, 0, 0)); -} - -struct dns_rr_txt * -dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx, - const struct in6_addr *addr, const char *dnsbl) { - return (struct dns_rr_txt *) - dns_resolve(ctx, dns_submit_a6dnsbl_txt(ctx, addr, dnsbl, 0, 0)); -} - -static int -dns_rhsbltodn(const char *name, const char *rhsbl, dnsc_t dn[DNS_MAXDN]) -{ - int l = dns_sptodn(name, dn, DNS_MAXDN); - if (l <= 0) return 0; - l = dns_sptodn(rhsbl, dn+l-1, DNS_MAXDN-l+1); - if (l <= 0) return 0; - return 1; -} - -struct dns_query * -dns_submit_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl, - dns_query_a4_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (!dns_rhsbltodn(name, rhsbl, dn)) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, - dns_parse_a4, (dns_query_fn*)cbck, data); -} -struct dns_query * -dns_submit_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl, - dns_query_txt_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - if (!dns_rhsbltodn(name, rhsbl, dn)) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, - dns_parse_txt, (dns_query_fn*)cbck, data); -} - -struct dns_rr_a4 * -dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl) { - return (struct dns_rr_a4*) - dns_resolve(ctx, dns_submit_rhsbl(ctx, name, rhsbl, 0, 0)); -} - -struct dns_rr_txt * -dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl) -{ - return (struct dns_rr_txt*) - dns_resolve(ctx, dns_submit_rhsbl_txt(ctx, name, rhsbl, 0, 0)); -} diff --git a/deps/udns/udns_dn.c b/deps/udns/udns_dn.c deleted file mode 100644 index 1264a1dc824..00000000000 --- a/deps/udns/udns_dn.c +++ /dev/null @@ -1,382 +0,0 @@ -/* $Id: udns_dn.c,v 1.7 2006/11/28 22:45:20 mjt Exp $ - domain names manipulation routines - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include "udns.h" - -unsigned dns_dnlen(dnscc_t *dn) { - register dnscc_t *d = dn; - while(*d) - d += 1 + *d; - return (unsigned)(d - dn) + 1; -} - -unsigned dns_dnlabels(register dnscc_t *dn) { - register unsigned l = 0; - while(*dn) - ++l, dn += 1 + *dn; - return l; -} - -unsigned dns_dnequal(register dnscc_t *dn1, register dnscc_t *dn2) { - register unsigned c; - dnscc_t *dn = dn1; - for(;;) { - if ((c = *dn1++) != *dn2++) - return 0; - if (!c) - return (unsigned)(dn1 - dn); - while(c--) { - if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2)) - return 0; - ++dn1; ++dn2; - } - } -} - -unsigned -dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz) { - unsigned sdnlen = dns_dnlen(sdn); - if (ddnsiz < sdnlen) - return 0; - memcpy(ddn, sdn, sdnlen); - return sdnlen; -} - -int -dns_ptodn(const char *name, unsigned namelen, - dnsc_t *dn, unsigned dnsiz, int *isabs) -{ - dnsc_t *dp; /* current position in dn (len byte first) */ - dnsc_t *const de /* end of dn: last byte that can be filled up */ - = dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1; - dnscc_t *np = (dnscc_t *)name; - dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np)); - dnsc_t *llab; /* start of last label (llab[-1] will be length) */ - unsigned c; /* next input character, or length of last label */ - - if (!dnsiz) - return 0; - dp = llab = dn + 1; - - while(np < ne) { - - if (*np == '.') { /* label delimiter */ - c = dp - llab; /* length of the label */ - if (!c) { /* empty label */ - if (np == (dnscc_t *)name && np + 1 == ne) { - /* special case for root dn, aka `.' */ - ++np; - break; - } - return -1; /* zero label */ - } - if (c > DNS_MAXLABEL) - return -1; /* label too long */ - llab[-1] = (dnsc_t)c; /* update len of last label */ - llab = ++dp; /* start new label, llab[-1] will be len of it */ - ++np; - continue; - } - - /* check whenever we may put out one more byte */ - if (dp >= de) /* too long? */ - return dnsiz >= DNS_MAXDN ? -1 : 0; - if (*np != '\\') { /* non-escape, simple case */ - *dp++ = *np++; - continue; - } - /* handle \-style escape */ - /* note that traditionally, domain names (gethostbyname etc) - * used decimal \dd notation, not octal \ooo (RFC1035), so - * we're following this tradition here. - */ - if (++np == ne) - return -1; /* bad escape */ - else if (*np >= '0' && *np <= '9') { /* decimal number */ - /* we allow not only exactly 3 digits as per RFC1035, - * but also 2 or 1, for better usability. */ - c = *np++ - '0'; - if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */ - c = c * 10 + *np++ - '0'; - if (np < ne && *np >= '0' && *np <= '9') { - c = c * 10 + *np++ - '0'; - if (c > 255) - return -1; /* bad escape */ - } - } - } - else - c = *np++; - *dp++ = (dnsc_t)c; /* place next out byte */ - } - - if ((c = dp - llab) > DNS_MAXLABEL) - return -1; /* label too long */ - if ((llab[-1] = (dnsc_t)c) != 0) { - *dp++ = 0; - if (isabs) - *isabs = 0; - } - else if (isabs) - *isabs = 1; - - return dp - dn; -} - -dnscc_t dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa"; - -dnsc_t * -dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne) { - dnsc_t *p; - unsigned n; - dnscc_t *s = ((dnscc_t *)addr) + 4; - while(--s >= (dnscc_t *)addr) { - n = *s; - p = dn + 1; - if (n > 99) { - if (p + 2 > dne) return 0; - *p++ = n / 100 + '0'; - *p++ = (n % 100 / 10) + '0'; - *p = n % 10 + '0'; - } - else if (n > 9) { - if (p + 1 > dne) return 0; - *p++ = n / 10 + '0'; - *p = n % 10 + '0'; - } - else { - if (p > dne) return 0; - *p = n + '0'; - } - *dn = p - dn; - dn = p + 1; - } - return dn; -} - -int dns_a4todn(const struct in_addr *addr, dnscc_t *tdn, - dnsc_t *dn, unsigned dnsiz) { - dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz); - dnsc_t *p; - unsigned l; - p = dns_a4todn_(addr, dn, dne); - if (!p) return 0; - if (!tdn) - tdn = dns_inaddr_arpa_dn; - l = dns_dnlen(tdn); - if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0; - memcpy(p, tdn, l); - return (p + l) - dn; -} - -int dns_a4ptodn(const struct in_addr *addr, const char *tname, - dnsc_t *dn, unsigned dnsiz) { - dnsc_t *p; - int r; - if (!tname) - return dns_a4todn(addr, NULL, dn, dnsiz); - p = dns_a4todn_(addr, dn, dn + dnsiz); - if (!p) return 0; - r = dns_sptodn(tname, p, dnsiz - (p - dn)); - return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0; -} - -dnscc_t dns_ip6_arpa_dn[10] = "\03ip6\04arpa"; - -dnsc_t * -dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne) { - unsigned n; - dnscc_t *s = ((dnscc_t *)addr) + 16; - if (dn + 64 > dne) return 0; - while(--s >= (dnscc_t *)addr) { - *dn++ = 1; - n = *s & 0x0f; - *dn++ = n > 9 ? n + 'a' - 10 : n + '0'; - *dn++ = 1; - n = *s >> 4; - *dn++ = n > 9 ? n + 'a' - 10 : n + '0'; - } - return dn; -} - -int dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn, - dnsc_t *dn, unsigned dnsiz) { - dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz); - dnsc_t *p; - unsigned l; - p = dns_a6todn_(addr, dn, dne); - if (!p) return 0; - if (!tdn) - tdn = dns_ip6_arpa_dn; - l = dns_dnlen(tdn); - if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0; - memcpy(p, tdn, l); - return (p + l) - dn; -} - -int dns_a6ptodn(const struct in6_addr *addr, const char *tname, - dnsc_t *dn, unsigned dnsiz) { - dnsc_t *p; - int r; - if (!tname) - return dns_a6todn(addr, NULL, dn, dnsiz); - p = dns_a6todn_(addr, dn, dn + dnsiz); - if (!p) return 0; - r = dns_sptodn(tname, p, dnsiz - (p - dn)); - return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0; -} - -/* return size of buffer required to convert the dn into asciiz string. - * Keep in sync with dns_dntop() below. - */ -unsigned dns_dntop_size(dnscc_t *dn) { - unsigned size = 0; /* the size reqd */ - dnscc_t *le; /* label end */ - - while(*dn) { - /* *dn is the length of the next label, non-zero */ - if (size) - ++size; /* for the dot */ - le = dn + *dn + 1; - ++dn; - do { - switch(*dn) { - case '.': - case '\\': - /* Special modifiers in zone files. */ - case '"': - case ';': - case '@': - case '$': - size += 2; - break; - default: - if (*dn <= 0x20 || *dn >= 0x7f) - /* \ddd decimal notation */ - size += 4; - else - size += 1; - } - } while(++dn < le); - } - size += 1; /* zero byte at the end - string terminator */ - return size > DNS_MAXNAME ? 0 : size; -} - -/* Convert the dn into asciiz string. - * Keep in sync with dns_dntop_size() above. - */ -int dns_dntop(dnscc_t *dn, char *name, unsigned namesiz) { - char *np = name; /* current name ptr */ - char *const ne = name + namesiz; /* end of name */ - dnscc_t *le; /* label end */ - - while(*dn) { - /* *dn is the length of the next label, non-zero */ - if (np != name) { - if (np >= ne) goto toolong; - *np++ = '.'; - } - le = dn + *dn + 1; - ++dn; - do { - switch(*dn) { - case '.': - case '\\': - /* Special modifiers in zone files. */ - case '"': - case ';': - case '@': - case '$': - if (np + 2 > ne) goto toolong; - *np++ = '\\'; - *np++ = *dn; - break; - default: - if (*dn <= 0x20 || *dn >= 0x7f) { - /* \ddd decimal notation */ - if (np + 4 >= ne) goto toolong; - *np++ = '\\'; - *np++ = '0' + (*dn / 100); - *np++ = '0' + ((*dn % 100) / 10); - *np++ = '0' + (*dn % 10); - } - else { - if (np >= ne) goto toolong; - *np++ = *dn; - } - } - } while(++dn < le); - } - if (np >= ne) goto toolong; - *np++ = '\0'; - return np - name; -toolong: - return namesiz >= DNS_MAXNAME ? -1 : 0; -} - -#ifdef TEST -#include -#include - -int main(int argc, char **argv) { - int i; - int sz; - dnsc_t dn[DNS_MAXDN+10]; - dnsc_t *dl, *dp; - int isabs; - - sz = (argc > 1) ? atoi(argv[1]) : 0; - - for(i = 2; i < argc; ++i) { - int r = dns_ptodn(argv[i], 0, dn, sz, &isabs); - printf("%s: ", argv[i]); - if (r < 0) printf("error\n"); - else if (!r) printf("buffer too small\n"); - else { - printf("len=%d dnlen=%d size=%d name:", - r, dns_dnlen(dn), dns_dntop_size(dn)); - dl = dn; - while(*dl) { - printf(" %d=", *dl); - dp = dl + 1; - dl = dp + *dl; - while(dp < dl) { - if (*dp <= ' ' || *dp >= 0x7f) - printf("\\%03d", *dp); - else if (*dp == '.' || *dp == '\\') - printf("\\%c", *dp); - else - putchar(*dp); - ++dp; - } - } - if (isabs) putchar('.'); - putchar('\n'); - } - } - return 0; -} - -#endif /* TEST */ diff --git a/deps/udns/udns_dntosp.c b/deps/udns/udns_dntosp.c deleted file mode 100644 index 933463e05a1..00000000000 --- a/deps/udns/udns_dntosp.c +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: udns_dntosp.c,v 1.5 2005/04/19 21:48:09 mjt Exp $ - dns_dntosp() = convert DN to asciiz string using static buffer - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include "udns.h" - -static char name[DNS_MAXNAME]; - -const char *dns_dntosp(dnscc_t *dn) { - return dns_dntop(dn, name, sizeof(name)) > 0 ? name : 0; -} diff --git a/deps/udns/udns_init.c b/deps/udns/udns_init.c deleted file mode 100644 index c0057313744..00000000000 --- a/deps/udns/udns_init.c +++ /dev/null @@ -1,231 +0,0 @@ -/* $Id: udns_init.c,v 1.6 2007/01/08 00:41:38 mjt Exp $ - resolver initialisation stuff - - Copyright (C) 2006 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#ifdef WINDOWS -# include /* includes */ -# include /* for dns server addresses etc */ -#else -# include -# include -# include -#endif /* !WINDOWS */ - -#include -#include -#include "udns.h" - -#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n') - -static const char space[] = " \t\r\n"; - -static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) { - dns_add_serv(ctx, NULL); - for(serv = strtok(serv, space); serv; serv = strtok(NULL, space)) - dns_add_serv(ctx, serv); -} - -static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) { - dns_add_srch(ctx, NULL); - for(srch = strtok(srch, space); srch; srch = strtok(NULL, space)) - dns_add_srch(ctx, srch); -} - -#ifdef WINDOWS - -#ifndef NO_IPHLPAPI -/* Apparently, some systems does not have proper headers for IPHLPAIP to work. - * The best is to upgrade headers, but here's another, ugly workaround for - * this: compile with -DNO_IPHLPAPI. - */ - -typedef DWORD (WINAPI *GetAdaptersAddressesFunc)( - ULONG Family, DWORD Flags, PVOID Reserved, - PIP_ADAPTER_ADDRESSES pAdapterAddresses, - PULONG pOutBufLen); - -static int dns_initns_iphlpapi(struct dns_ctx *ctx) { - HANDLE h_iphlpapi; - GetAdaptersAddressesFunc pfnGetAdAddrs; - PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf; - PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr; - ULONG ulOutBufLen; - DWORD dwRetVal; - int ret = -1; - - h_iphlpapi = LoadLibrary("iphlpapi.dll"); - if (!h_iphlpapi) - return -1; - pfnGetAdAddrs = (GetAdaptersAddressesFunc) - GetProcAddress(h_iphlpapi, "GetAdaptersAddresses"); - if (!pfnGetAdAddrs) goto freelib; - ulOutBufLen = 0; - dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen); - if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib; - pAddrBuf = malloc(ulOutBufLen); - if (!pAddrBuf) goto freelib; - dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen); - if (dwRetVal != ERROR_SUCCESS) goto freemem; - for (pAddr = pAddrBuf; pAddr; pAddr = pAddr->Next) - for (pDnsAddr = pAddr->FirstDnsServerAddress; - pDnsAddr; - pDnsAddr = pDnsAddr->Next) - dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr); - ret = 0; -freemem: - free(pAddrBuf); -freelib: - FreeLibrary(h_iphlpapi); - return ret; -} - -#else /* NO_IPHLPAPI */ - -#define dns_initns_iphlpapi(ctx) (-1) - -#endif /* NO_IPHLPAPI */ - -static int dns_initns_registry(struct dns_ctx *ctx) { - LONG res; - HKEY hk; - DWORD type = REG_EXPAND_SZ | REG_SZ; - DWORD len; - char valBuf[1024]; - -#define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters" -#define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP" - res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk); - if (res != ERROR_SUCCESS) - res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x, - 0, KEY_QUERY_VALUE, &hk); - if (res != ERROR_SUCCESS) - return -1; - len = sizeof(valBuf) - 1; - res = RegQueryValueEx(hk, "NameServer", NULL, &type, (BYTE*)valBuf, &len); - if (res != ERROR_SUCCESS || !len || !valBuf[0]) { - len = sizeof(valBuf) - 1; - res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type, - (BYTE*)valBuf, &len); - } - RegCloseKey(hk); - if (res != ERROR_SUCCESS || !len || !valBuf[0]) - return -1; - valBuf[len] = '\0'; - /* nameservers are stored as a whitespace-seperate list: - * "192.168.1.1 123.21.32.12" */ - dns_set_serv_internal(ctx, valBuf); - return 0; -} - -#else /* !WINDOWS */ - -static int dns_init_resolvconf(struct dns_ctx *ctx) { - char *v; - char buf[2049]; /* this buffer is used to hold /etc/resolv.conf */ - int has_srch = 0; - - /* read resolv.conf... */ - { int fd = open("/etc/resolv.conf", O_RDONLY); - if (fd >= 0) { - int l = read(fd, buf, sizeof(buf) - 1); - close(fd); - buf[l < 0 ? 0 : l] = '\0'; - } - else - buf[0] = '\0'; - } - if (buf[0]) { /* ...and parse it */ - char *line, *nextline; - line = buf; - do { - nextline = strchr(line, '\n'); - if (nextline) *nextline++ = '\0'; - v = line; - while(*v && !ISSPACE(*v)) ++v; - if (!*v) continue; - *v++ = '\0'; - while(ISSPACE(*v)) ++v; - if (!*v) continue; - if (strcmp(line, "domain") == 0) { - dns_set_srch_internal(ctx, strtok(v, space)); - has_srch = 1; - } - else if (strcmp(line, "search") == 0) { - dns_set_srch_internal(ctx, v); - has_srch = 1; - } - else if (strcmp(line, "nameserver") == 0) - dns_add_serv(ctx, strtok(v, space)); - else if (strcmp(line, "options") == 0) - dns_set_opts(ctx, v); - } while((line = nextline) != NULL); - } - - buf[sizeof(buf)-1] = '\0'; - - /* get list of nameservers from env. vars. */ - if ((v = getenv("NSCACHEIP")) != NULL || - (v = getenv("NAMESERVERS")) != NULL) { - strncpy(buf, v, sizeof(buf) - 1); - dns_set_serv_internal(ctx, buf); - } - /* if $LOCALDOMAIN is set, use it for search list */ - if ((v = getenv("LOCALDOMAIN")) != NULL) { - strncpy(buf, v, sizeof(buf) - 1); - dns_set_srch_internal(ctx, buf); - has_srch = 1; - } - if ((v = getenv("RES_OPTIONS")) != NULL) - dns_set_opts(ctx, v); - - /* if still no search list, use local domain name */ - if (has_srch && - gethostname(buf, sizeof(buf) - 1) == 0 && - (v = strchr(buf, '.')) != NULL && - *++v != '\0') - dns_add_srch(ctx, v); - - return 0; -} - -#endif /* !WINDOWS */ - -int dns_init(struct dns_ctx *ctx, int do_open) { - if (!ctx) - ctx = &dns_defctx; - dns_reset(ctx); - -#ifdef WINDOWS - if (dns_initns_iphlpapi(ctx) != 0) - dns_initns_registry(ctx); - /*XXX WINDOWS: probably good to get default domain and search list too... - * And options. Something is in registry. */ - /*XXX WINDOWS: maybe environment variables are also useful? */ -#else - dns_init_resolvconf(ctx); -#endif - - return do_open ? dns_open(ctx) : 0; -} diff --git a/deps/udns/udns_misc.c b/deps/udns/udns_misc.c deleted file mode 100644 index 0db7ffd145b..00000000000 --- a/deps/udns/udns_misc.c +++ /dev/null @@ -1,67 +0,0 @@ -/* $Id: udns_misc.c,v 1.8 2005/04/05 22:51:32 mjt Exp $ - miscellaneous routines - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include "udns.h" - -int dns_findname(const struct dns_nameval *nv, const char *name) { - register const char *a, *b; - for(; nv->name; ++nv) - for(a = name, b = nv->name; ; ++a, ++b) - if (DNS_DNUC(*a) != *b) break; - else if (!*a) return nv->val; - return -1; -} - -const char *_dns_format_code(char *buf, const char *prefix, int code) { - char *bp = buf; - unsigned c, n; - do *bp++ = DNS_DNUC(*prefix); - while(*++prefix); - *bp++ = '#'; - if (code < 0) code = -code, *bp++ = '-'; - n = 0; c = code; - do ++n; - while((c /= 10)); - c = code; - bp[n--] = '\0'; - do bp[n--] = c % 10 + '0'; - while((c /= 10)); - return buf; -} - -const char *dns_strerror(int err) { - if (err >= 0) return "successeful completion"; - switch(err) { - case DNS_E_TEMPFAIL: return "temporary failure in name resolution"; - case DNS_E_PROTOCOL: return "protocol error"; - case DNS_E_NXDOMAIN: return "domain name does not exist"; - case DNS_E_NODATA: return "valid domain but no data of requested type"; - case DNS_E_NOMEM: return "out of memory"; - case DNS_E_BADQUERY: return "malformed query"; - default: return "unknown error"; - } -} - -const char *dns_version(void) { - return UDNS_VERSION; -} diff --git a/deps/udns/udns_parse.c b/deps/udns/udns_parse.c deleted file mode 100644 index 5440d924140..00000000000 --- a/deps/udns/udns_parse.c +++ /dev/null @@ -1,169 +0,0 @@ -/* $Id: udns_parse.c,v 1.14 2005/09/12 10:55:21 mjt Exp $ - raw DNS packet parsing routines - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include "udns.h" - -dnscc_t *dns_skipdn(dnscc_t *cur, dnscc_t *end) { - unsigned c; - for(;;) { - if (cur >= end) - return NULL; - c = *cur++; - if (!c) - return cur; - if (c & 192) /* jump */ - return cur + 1 >= end ? NULL : cur + 1; - cur += c; - } -} - -int -dns_getdn(dnscc_t *pkt, dnscc_t **cur, dnscc_t *end, - register dnsc_t *dn, unsigned dnsiz) { - unsigned c; - dnscc_t *pp = *cur; /* current packet pointer */ - dnsc_t *dp = dn; /* current dn pointer */ - dnsc_t *const de /* end of the DN dest */ - = dn + (dnsiz < DNS_MAXDN ? dnsiz : DNS_MAXDN); - dnscc_t *jump = NULL; /* ptr after first jump if any */ - unsigned loop = 100; /* jump loop counter */ - - for(;;) { /* loop by labels */ - if (pp >= end) /* reached end of packet? */ - return -1; - c = *pp++; /* length of the label */ - if (!c) { /* empty label: terminate */ - if (dn >= de) /* can't fit terminator */ - goto noroom; - *dp++ = 0; - /* return next pos: either after the first jump or current */ - *cur = jump ? jump : pp; - return dp - dn; - } - if (c & 192) { /* jump */ - if (pp >= end) /* eop instead of jump pos */ - return -1; - if (!jump) jump = pp + 1; /* remember first jump */ - else if (!--loop) return -1; /* too many jumps */ - c = ((c & ~192) << 8) | *pp; /* new pos */ - if (c < DNS_HSIZE) /* don't allow jump into the header */ - return -1; - pp = pkt + c; - continue; - } - if (c > DNS_MAXLABEL) /* too long label? */ - return -1; - if (pp + c > end) /* label does not fit in packet? */ - return -1; - if (dp + c + 1 > de) /* if enouth room for the label */ - goto noroom; - *dp++ = c; /* label length */ - memcpy(dp, pp, c); /* and the label itself */ - dp += c; - pp += c; /* advance to the next label */ - } -noroom: - return dnsiz < DNS_MAXDN ? 0 : -1; -} - -void dns_rewind(struct dns_parse *p, dnscc_t *qdn) { - p->dnsp_qdn = qdn; - p->dnsp_cur = p->dnsp_ans; - p->dnsp_rrl = dns_numan(p->dnsp_pkt); - p->dnsp_ttl = 0xffffffffu; - p->dnsp_nrr = 0; -} - -void -dns_initparse(struct dns_parse *p, dnscc_t *qdn, - dnscc_t *pkt, dnscc_t *cur, dnscc_t *end) { - p->dnsp_pkt = pkt; - p->dnsp_end = end; - p->dnsp_rrl = dns_numan(pkt); - p->dnsp_qdn = qdn; - assert(cur + 4 <= end); - if ((p->dnsp_qtyp = dns_get16(cur+0)) == DNS_T_ANY) p->dnsp_qtyp = 0; - if ((p->dnsp_qcls = dns_get16(cur+2)) == DNS_C_ANY) p->dnsp_qcls = 0; - p->dnsp_cur = p->dnsp_ans = cur + 4; - p->dnsp_ttl = 0xffffffffu; - p->dnsp_nrr = 0; -} - -int dns_nextrr(struct dns_parse *p, struct dns_rr *rr) { - dnscc_t *cur = p->dnsp_cur; - while(p->dnsp_rrl > 0) { - --p->dnsp_rrl; - if (dns_getdn(p->dnsp_pkt, &cur, p->dnsp_end, - rr->dnsrr_dn, sizeof(rr->dnsrr_dn)) <= 0) - return -1; - if (cur + 10 > p->dnsp_end) - return -1; - rr->dnsrr_typ = dns_get16(cur); - rr->dnsrr_cls = dns_get16(cur+2); - rr->dnsrr_ttl = dns_get32(cur+4); - rr->dnsrr_dsz = dns_get16(cur+8); - rr->dnsrr_dptr = cur = cur + 10; - rr->dnsrr_dend = cur = cur + rr->dnsrr_dsz; - if (cur > p->dnsp_end) - return -1; - if (p->dnsp_qdn && !dns_dnequal(p->dnsp_qdn, rr->dnsrr_dn)) - continue; - if ((!p->dnsp_qcls || p->dnsp_qcls == rr->dnsrr_cls) && - (!p->dnsp_qtyp || p->dnsp_qtyp == rr->dnsrr_typ)) { - p->dnsp_cur = cur; - ++p->dnsp_nrr; - if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl; - return 1; - } - if (p->dnsp_qdn && rr->dnsrr_typ == DNS_T_CNAME && !p->dnsp_nrr) { - if (dns_getdn(p->dnsp_pkt, &rr->dnsrr_dptr, p->dnsp_end, - p->dnsp_dnbuf, sizeof(p->dnsp_dnbuf)) <= 0 || - rr->dnsrr_dptr != rr->dnsrr_dend) - return -1; - p->dnsp_qdn = p->dnsp_dnbuf; - if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl; - } - } - p->dnsp_cur = cur; - return 0; -} - -int dns_stdrr_size(const struct dns_parse *p) { - return - dns_dntop_size(p->dnsp_qdn) + - (p->dnsp_qdn == dns_payload(p->dnsp_pkt) ? 0 : - dns_dntop_size(dns_payload(p->dnsp_pkt))); -} - -void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp, - const struct dns_parse *p) { - cp += dns_dntop(p->dnsp_qdn, (ret->dnsn_cname = cp), DNS_MAXNAME); - if (p->dnsp_qdn == dns_payload(p->dnsp_pkt)) - ret->dnsn_qname = ret->dnsn_cname; - else - dns_dntop(dns_payload(p->dnsp_pkt), (ret->dnsn_qname = cp), DNS_MAXNAME); - ret->dnsn_ttl = p->dnsp_ttl; - return ret; -} diff --git a/deps/udns/udns_resolver.c b/deps/udns/udns_resolver.c deleted file mode 100644 index d083397d4d3..00000000000 --- a/deps/udns/udns_resolver.c +++ /dev/null @@ -1,1294 +0,0 @@ -/* $Id: udns_resolver.c,v 1.98 2007/01/10 13:32:33 mjt Exp $ - resolver stuff (main module) - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#ifdef WINDOWS -# include /* includes */ -# include /* needed for struct in6_addr */ -#else -# include -# include -# include -# include -# include -# include -# ifdef HAVE_POLL -# include -# else -# ifdef HAVE_SYS_SELECT_H -# include -# endif -# endif -# ifdef HAVE_TIMES -# include -# endif -# define closesocket(sock) close(sock) -#endif /* !WINDOWS */ - -#include -#include -#include -#include -#include -#include -#include "udns.h" - -#ifndef EAFNOSUPPORT -# define EAFNOSUPPORT EINVAL -#endif -#ifndef MSG_DONTWAIT -# define MSG_DONTWAIT 0 -#endif - -struct dns_qlink { - struct dns_query *next, *prev; -}; - -struct dns_query { - struct dns_qlink dnsq_link; /* list entry (should be first) */ - unsigned dnsq_origdnl0; /* original query DN len w/o last 0 */ - unsigned dnsq_flags; /* control flags for this query */ - unsigned dnsq_servi; /* index of next server to try */ - unsigned dnsq_servwait; /* bitmask: servers left to wait */ - unsigned dnsq_servskip; /* bitmask: servers to skip */ - unsigned dnsq_servnEDNS0; /* bitmask: servers refusing EDNS0 */ - unsigned dnsq_try; /* number of tries made so far */ - dnscc_t *dnsq_nxtsrch; /* next search pointer @dnsc_srchbuf */ - time_t dnsq_deadline; /* when current try will expire */ - dns_parse_fn *dnsq_parse; /* parse: raw => application */ - dns_query_fn *dnsq_cbck; /* the callback to call when done */ - void *dnsq_cbdata; /* user data for the callback */ -#ifndef NDEBUG - struct dns_ctx *dnsq_ctx; /* the resolver context */ -#endif - /* char fields at the end to avoid padding */ - dnsc_t dnsq_id[2]; /* query ID */ - dnsc_t dnsq_typcls[4]; /* requested RR type+class */ - dnsc_t dnsq_dn[DNS_MAXDN+DNS_DNPAD]; /* the query DN +alignment */ -}; - -/* working with dns_query lists */ - -static __inline void qlist_init(struct dns_qlink *list) { - list->next = list->prev = (struct dns_query *)list; -} - -static __inline int qlist_isempty(const struct dns_qlink *list) { - return list->next == (const struct dns_query *)list ? 1 : 0; -} - -static __inline struct dns_query *qlist_first(struct dns_qlink *list) { - return list->next == (struct dns_query *)list ? 0 : list->next; -} - -static __inline void qlist_remove(struct dns_query *q) { - q->dnsq_link.next->dnsq_link.prev = q->dnsq_link.prev; - q->dnsq_link.prev->dnsq_link.next = q->dnsq_link.next; -} - -/* insert q between prev and next */ -static __inline void -qlist_insert(struct dns_query *q, - struct dns_query *prev, struct dns_query *next) { - q->dnsq_link.next = next; - q->dnsq_link.prev = prev; - prev->dnsq_link.next = next->dnsq_link.prev = q; -} - -static __inline void -qlist_insert_after(struct dns_query *q, struct dns_query *prev) { - qlist_insert(q, prev, prev->dnsq_link.next); -} - -static __inline void -qlist_insert_before(struct dns_query *q, struct dns_query *next) { - qlist_insert(q, next->dnsq_link.prev, next); -} - -static __inline void -qlist_add_tail(struct dns_query *q, struct dns_qlink *top) { - qlist_insert_before(q, (struct dns_query *)top); -} - -static __inline void -qlist_add_head(struct dns_query *q, struct dns_qlink *top) { - qlist_insert_after(q, (struct dns_query *)top); -} - -#define QLIST_FIRST(list, direction) ((list)->direction) -#define QLIST_ISLAST(list, q) ((q) == (struct dns_query*)(list)) -#define QLIST_NEXT(q, direction) ((q)->dnsq_link.direction) - -#define QLIST_FOR_EACH(list, q, direction) \ - for(q = QLIST_FIRST(list, direction); \ - !QLIST_ISLAST(list, q); q = QLIST_NEXT(q, direction)) - -union sockaddr_ns { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef HAVE_IPv6 - struct sockaddr_in6 sin6; -#endif -}; - -#define sin_eq(a,b) \ - ((a).sin_port == (b).sin_port && \ - (a).sin_addr.s_addr == (b).sin_addr.s_addr) -#define sin6_eq(a,b) \ - ((a).sin6_port == (b).sin6_port && \ - memcmp(&(a).sin6_addr, &(b).sin6_addr, sizeof(struct in6_addr)) == 0) - -struct dns_ctx { /* resolver context */ - /* settings */ - unsigned dnsc_flags; /* various flags */ - unsigned dnsc_timeout; /* timeout (base value) for queries */ - unsigned dnsc_ntries; /* number of retries */ - unsigned dnsc_ndots; /* ndots to assume absolute name */ - unsigned dnsc_port; /* default port (DNS_PORT) */ - unsigned dnsc_udpbuf; /* size of UDP buffer */ - /* array of nameserver addresses */ - union sockaddr_ns dnsc_serv[DNS_MAXSERV]; - unsigned dnsc_nserv; /* number of nameservers */ - unsigned dnsc_salen; /* length of socket addresses */ - dnsc_t dnsc_srchbuf[1024]; /* buffer for searchlist */ - dnsc_t *dnsc_srchend; /* current end of srchbuf */ - - dns_utm_fn *dnsc_utmfn; /* register/cancel timer events */ - void *dnsc_utmctx; /* user timer context for utmfn() */ - time_t dnsc_utmexp; /* when user timer expires */ - - dns_dbgfn *dnsc_udbgfn; /* debugging function */ - - /* dynamic data */ - unsigned dnsc_nextid; /* next queue ID to use */ - int dnsc_udpsock; /* UDP socket */ - struct dns_qlink dnsc_qactive; /* active list sorted by deadline */ - int dnsc_nactive; /* number entries in dnsc_qactive */ - dnsc_t *dnsc_pbuf; /* packet buffer (udpbuf size) */ - int dnsc_qstatus; /* last query status value */ -}; - -static const struct { - const char *name; - enum dns_opt opt; - unsigned offset; - unsigned min, max; -} dns_opts[] = { -#define opt(name,opt,field,min,max) \ - {name,opt,offsetof(struct dns_ctx,field),min,max} - opt("retrans", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300), - opt("timeout", DNS_OPT_TIMEOUT, dnsc_timeout, 1,300), - opt("retry", DNS_OPT_NTRIES, dnsc_ntries, 1,50), - opt("attempts", DNS_OPT_NTRIES, dnsc_ntries, 1,50), - opt("ndots", DNS_OPT_NDOTS, dnsc_ndots, 0,1000), - opt("port", DNS_OPT_PORT, dnsc_port, 1,0xffff), - opt("udpbuf", DNS_OPT_UDPSIZE, dnsc_udpbuf, DNS_MAXPACKET,65536), -#undef opt -}; -#define dns_ctxopt(ctx,idx) (*((unsigned*)(((char*)ctx)+dns_opts[idx].offset))) - -#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n') - -struct dns_ctx dns_defctx; - -#define SETCTX(ctx) if (!ctx) ctx = &dns_defctx -#define SETCTXINITED(ctx) SETCTX(ctx); assert(CTXINITED(ctx)) -#define CTXINITED(ctx) (ctx->dnsc_flags & DNS_INITED) -#define SETCTXFRESH(ctx) SETCTXINITED(ctx); assert(!CTXOPEN(ctx)) -#define SETCTXINACTIVE(ctx) \ - SETCTXINITED(ctx); assert(!ctx->dnsc_nactive) -#define SETCTXOPEN(ctx) SETCTXINITED(ctx); assert(CTXOPEN(ctx)) -#define CTXOPEN(ctx) (ctx->dnsc_udpsock >= 0) - -#if defined(NDEBUG) || !defined(DEBUG) -#define dns_assert_ctx(ctx) -#else -static void dns_assert_ctx(const struct dns_ctx *ctx) { - int nactive = 0; - const struct dns_query *q; - QLIST_FOR_EACH(&ctx->dnsc_qactive, q, next) { - assert(q->dnsq_ctx == ctx); - assert(q->dnsq_link.next->dnsq_link.prev == q); - assert(q->dnsq_link.prev->dnsq_link.next == q); - ++nactive; - } - assert(nactive == ctx->dnsc_nactive); -} -#endif - -enum { - DNS_INTERNAL = 0xffff, /* internal flags mask */ - DNS_INITED = 0x0001, /* the context is initialized */ - DNS_ASIS_DONE = 0x0002, /* search: skip the last as-is query */ - DNS_SEEN_NODATA = 0x0004, /* search: NODATA has been received */ -}; - -int dns_add_serv(struct dns_ctx *ctx, const char *serv) { - union sockaddr_ns *sns; - SETCTXFRESH(ctx); - if (!serv) - return (ctx->dnsc_nserv = 0); - if (ctx->dnsc_nserv >= DNS_MAXSERV) - return errno = ENFILE, -1; - sns = &ctx->dnsc_serv[ctx->dnsc_nserv]; - memset(sns, 0, sizeof(*sns)); - if (dns_pton(AF_INET, serv, &sns->sin.sin_addr) > 0) { - sns->sin.sin_family = AF_INET; - return ++ctx->dnsc_nserv; - } -#ifdef HAVE_IPv6 - if (dns_pton(AF_INET6, serv, &sns->sin6.sin6_addr) > 0) { - sns->sin6.sin6_family = AF_INET6; - return ++ctx->dnsc_nserv; - } -#endif - errno = EINVAL; - return -1; -} - -int dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa) { - SETCTXFRESH(ctx); - if (!sa) - return (ctx->dnsc_nserv = 0); - if (ctx->dnsc_nserv >= DNS_MAXSERV) - return errno = ENFILE, -1; -#ifdef HAVE_IPv6 - else if (sa->sa_family == AF_INET6) - ctx->dnsc_serv[ctx->dnsc_nserv].sin6 = *(struct sockaddr_in6*)sa; -#endif - else if (sa->sa_family == AF_INET) - ctx->dnsc_serv[ctx->dnsc_nserv].sin = *(struct sockaddr_in*)sa; - else - return errno = EAFNOSUPPORT, -1; - return ++ctx->dnsc_nserv; -} - -int dns_set_opts(struct dns_ctx *ctx, const char *opts) { - unsigned i, v; - SETCTXINACTIVE(ctx); - for(;;) { - while(ISSPACE(*opts)) ++opts; - if (!*opts) break; - for(i = 0; i < sizeof(dns_opts)/sizeof(dns_opts[0]); ++i) { - v = strlen(dns_opts[i].name); - if (strncmp(dns_opts[i].name, opts, v) != 0 || - (opts[v] != ':' && opts[v] != '=')) - continue; - opts += v + 1; - v = 0; - if (*opts < '0' || *opts > '9') break; - do v = v * 10 + (*opts++ - '0'); - while (*opts >= '0' && *opts <= '9'); - if (v < dns_opts[i].min) v = dns_opts[i].min; - if (v > dns_opts[i].max) v = dns_opts[i].max; - dns_ctxopt(ctx, i) = v; - break; - } - while(*opts && !ISSPACE(*opts)) ++opts; - } - return 0; -} - -int dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val) { - int prev; - unsigned i; - SETCTXINACTIVE(ctx); - for(i = 0; i < sizeof(dns_opts)/sizeof(dns_opts[0]); ++i) { - if (dns_opts[i].opt != opt) continue; - prev = dns_ctxopt(ctx, i); - if (val >= 0) { - unsigned v = val; - if (v < dns_opts[i].min || v > dns_opts[i].max) { - errno = EINVAL; - return -1; - } - dns_ctxopt(ctx, i) = v; - } - return prev; - } - if (opt == DNS_OPT_FLAGS) { - prev = ctx->dnsc_flags & ~DNS_INTERNAL; - if (val >= 0) - ctx->dnsc_flags = - (ctx->dnsc_flags & DNS_INTERNAL) | (val & ~DNS_INTERNAL); - return prev; - } - errno = ENOSYS; - return -1; -} - -int dns_add_srch(struct dns_ctx *ctx, const char *srch) { - int dnl; - SETCTXINACTIVE(ctx); - if (!srch) { - memset(ctx->dnsc_srchbuf, 0, sizeof(ctx->dnsc_srchbuf)); - ctx->dnsc_srchend = ctx->dnsc_srchbuf; - return 0; - } - dnl = - sizeof(ctx->dnsc_srchbuf) - (ctx->dnsc_srchend - ctx->dnsc_srchbuf) - 1; - dnl = dns_sptodn(srch, ctx->dnsc_srchend, dnl); - if (dnl > 0) - ctx->dnsc_srchend += dnl; - ctx->dnsc_srchend[0] = '\0'; /* we ensure the list is always ends at . */ - if (dnl > 0) - return 0; - errno = EINVAL; - return -1; -} - -static void dns_drop_utm(struct dns_ctx *ctx) { - if (ctx->dnsc_utmfn) - ctx->dnsc_utmfn(NULL, -1, ctx->dnsc_utmctx); - ctx->dnsc_utmctx = NULL; - ctx->dnsc_utmexp = -1; -} - -static void -_dns_request_utm(struct dns_ctx *ctx, time_t now) { - struct dns_query *q; - time_t deadline; - int timeout; - q = qlist_first(&ctx->dnsc_qactive); - if (!q) - deadline = -1, timeout = -1; - else if (!now || q->dnsq_deadline <= now) - deadline = 0, timeout = 0; - else - deadline = q->dnsq_deadline, timeout = (int)(deadline - now); - if (ctx->dnsc_utmexp == deadline) - return; - ctx->dnsc_utmfn(ctx, timeout, ctx->dnsc_utmctx); - ctx->dnsc_utmexp = deadline; -} - -static __inline void -dns_request_utm(struct dns_ctx *ctx, time_t now) { - if (ctx->dnsc_utmfn) - _dns_request_utm(ctx, now); -} - -void dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn) { - SETCTXINITED(ctx); - ctx->dnsc_udbgfn = dbgfn; -} - -void -dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data) { - SETCTXINITED(ctx); - dns_drop_utm(ctx); - ctx->dnsc_utmfn = fn; - ctx->dnsc_utmctx = data; - if (CTXOPEN(ctx)) - dns_request_utm(ctx, 0); -} - -unsigned dns_random16(void) { -#ifdef WINDOWS - FILETIME ft; - GetSystemTimeAsFileTime(&ft); -#define x (ft.dwLowDateTime) -#else - struct timeval tv; - gettimeofday(&tv, NULL); -#define x (tv.tv_usec) -#endif - return ((unsigned)x ^ ((unsigned)x >> 16)) & 0xffff; -#undef x -} - -void dns_close(struct dns_ctx *ctx) { - struct dns_query *q; - SETCTX(ctx); - if (CTXINITED(ctx)) { - if (ctx->dnsc_udpsock >= 0) - closesocket(ctx->dnsc_udpsock); - ctx->dnsc_udpsock = -1; - if (ctx->dnsc_pbuf) - free(ctx->dnsc_pbuf); - ctx->dnsc_pbuf = NULL; - while((q = qlist_first(&ctx->dnsc_qactive)) != NULL) { - qlist_remove(q); - free(q); - } - ctx->dnsc_nactive = 0; - dns_drop_utm(ctx); - } -} - -void dns_reset(struct dns_ctx *ctx) { - SETCTX(ctx); - dns_close(ctx); - memset(ctx, 0, sizeof(*ctx)); - ctx->dnsc_timeout = 4; - ctx->dnsc_ntries = 3; - ctx->dnsc_ndots = 1; - ctx->dnsc_udpbuf = DNS_EDNS0PACKET; - ctx->dnsc_port = DNS_PORT; - ctx->dnsc_udpsock = -1; - ctx->dnsc_srchend = ctx->dnsc_srchbuf; - qlist_init(&ctx->dnsc_qactive); - ctx->dnsc_nextid = dns_random16(); - ctx->dnsc_flags = DNS_INITED; -} - -struct dns_ctx *dns_new(const struct dns_ctx *copy) { - struct dns_ctx *ctx; - SETCTXINITED(copy); - dns_assert_ctx(copy); - ctx = malloc(sizeof(*ctx)); - if (!ctx) - return NULL; - *ctx = *copy; - ctx->dnsc_udpsock = -1; - qlist_init(&ctx->dnsc_qactive); - ctx->dnsc_nactive = 0; - ctx->dnsc_pbuf = NULL; - ctx->dnsc_qstatus = 0; - ctx->dnsc_utmfn = NULL; - ctx->dnsc_utmctx = NULL; - ctx->dnsc_nextid = dns_random16(); - return ctx; -} - -void dns_free(struct dns_ctx *ctx) { - assert(ctx != NULL && ctx != &dns_defctx); - dns_reset(ctx); - free(ctx); -} - -int dns_open(struct dns_ctx *ctx) { - int sock; - unsigned i; - int port; - union sockaddr_ns *sns; -#ifdef HAVE_IPv6 - unsigned have_inet6 = 0; -#endif - - SETCTXINITED(ctx); - assert(!CTXOPEN(ctx)); - - port = htons((unsigned short)ctx->dnsc_port); - /* ensure we have at least one server */ - if (!ctx->dnsc_nserv) { - sns = ctx->dnsc_serv; - sns->sin.sin_family = AF_INET; - sns->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - ctx->dnsc_nserv = 1; - } - - for (i = 0; i < ctx->dnsc_nserv; ++i) { - sns = &ctx->dnsc_serv[i]; - /* set port for each sockaddr */ -#ifdef HAVE_IPv6 - if (sns->sa.sa_family == AF_INET6) { - if (!sns->sin6.sin6_port) sns->sin6.sin6_port = (unsigned short)port; - ++have_inet6; - } - else -#endif - { - assert(sns->sa.sa_family == AF_INET); - if (!sns->sin.sin_port) sns->sin.sin_port = (unsigned short)port; - } - } - -#ifdef HAVE_IPv6 - if (have_inet6 && have_inet6 < ctx->dnsc_nserv) { - /* convert all IPv4 addresses to IPv6 V4MAPPED */ - struct sockaddr_in6 sin6; - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - /* V4MAPPED: ::ffff:1.2.3.4 */ - sin6.sin6_addr.s6_addr[10] = 0xff; - sin6.sin6_addr.s6_addr[11] = 0xff; - for(i = 0; i < ctx->dnsc_nserv; ++i) { - sns = &ctx->dnsc_serv[i]; - if (sns->sa.sa_family == AF_INET) { - sin6.sin6_port = sns->sin.sin_port; - ((struct in_addr*)&sin6.sin6_addr)[3] = sns->sin.sin_addr; - sns->sin6 = sin6; - } - } - } - - ctx->dnsc_salen = have_inet6 ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); - - if (have_inet6) - sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); - else - sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); -#else /* !HAVE_IPv6 */ - sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - ctx->dnsc_salen = sizeof(struct sockaddr_in); -#endif /* HAVE_IPv6 */ - - if (sock < 0) { - ctx->dnsc_qstatus = DNS_E_TEMPFAIL; - return -1; - } -#ifdef WINDOWS - { unsigned long on = 1; - if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) { - closesocket(sock); - ctx->dnsc_qstatus = DNS_E_TEMPFAIL; - return -1; - } - } -#else /* !WINDOWS */ - if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0 || - fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) { - closesocket(sock); - ctx->dnsc_qstatus = DNS_E_TEMPFAIL; - return -1; - } -#endif /* WINDOWS */ - /* allocate the packet buffer */ - if ((ctx->dnsc_pbuf = malloc(ctx->dnsc_udpbuf)) == NULL) { - closesocket(sock); - ctx->dnsc_qstatus = DNS_E_NOMEM; - errno = ENOMEM; - return -1; - } - - ctx->dnsc_udpsock = sock; - dns_request_utm(ctx, 0); - return sock; -} - -int dns_sock(const struct dns_ctx *ctx) { - SETCTXINITED(ctx); - return ctx->dnsc_udpsock; -} - -int dns_active(const struct dns_ctx *ctx) { - SETCTXINITED(ctx); - dns_assert_ctx(ctx); - return ctx->dnsc_nactive; -} - -int dns_status(const struct dns_ctx *ctx) { - SETCTX(ctx); - return ctx->dnsc_qstatus; -} -void dns_setstatus(struct dns_ctx *ctx, int status) { - SETCTX(ctx); - ctx->dnsc_qstatus = status; -} - -/* End the query: disconnect it from the active list, free it, - * and return the result to the caller. - */ -static void -dns_end_query(struct dns_ctx *ctx, struct dns_query *q, - int status, void *result) { - dns_query_fn *cbck = q->dnsq_cbck; - void *cbdata = q->dnsq_cbdata; - ctx->dnsc_qstatus = status; - assert((status < 0 && result == 0) || (status >= 0 && result != 0)); - assert(cbck != 0); /*XXX callback may be NULL */ - assert(ctx->dnsc_nactive > 0); - --ctx->dnsc_nactive; - qlist_remove(q); - /* force the query to be unconnected */ - /*memset(q, 0, sizeof(*q));*/ -#ifndef NDEBUG - q->dnsq_ctx = NULL; -#endif - free(q); - cbck(ctx, result, cbdata); -} - -#define DNS_DBG(ctx, code, sa, slen, pkt, plen) \ - do { \ - if (ctx->dnsc_udbgfn) \ - ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, 0, 0); \ - } while(0) -#define DNS_DBGQ(ctx, q, code, sa, slen, pkt, plen) \ - do { \ - if (ctx->dnsc_udbgfn) \ - ctx->dnsc_udbgfn(code, (sa), slen, pkt, plen, q, q->dnsq_cbdata); \ - } while(0) - -static void dns_newid(struct dns_ctx *ctx, struct dns_query *q) { - /* this is how we choose an identifier for a new query (qID). - * For now, it's just sequential number, incremented for every query, and - * thus obviously trivial to guess. - * There are two choices: - * a) use sequential numbers. It is plain insecure. In DNS, there are two - * places where random numbers are (or can) be used to increase security: - * random qID and random source port number. Without this randomness - * (udns uses fixed port for all queries), or when the randomness is weak, - * it's trivial to spoof query replies. With randomness however, it - * becomes a bit more difficult task. Too bad we only have 16 bits for - * our security, as qID is only two bytes. It isn't a security per se, - * to rely on those 16 bits - an attacker can just flood us with fake - * replies with all possible qIDs (only 65536 of them), and in this case, - * even if we'll use true random qIDs, we'll be in trouble (not protected - * against spoofing). Yes, this is only possible on a high-speed network - * (probably on the LAN only, since usually a border router for a LAN - * protects internal machines from packets with spoofed local addresses - * from outside, and usually a nameserver resides on LAN), but it's - * still very well possible to send us fake replies. - * In other words: there's nothing a DNS (stub) resolver can do against - * spoofing attacks, unless DNSSEC is in use, which helps here alot. - * Too bad that DNSSEC isn't widespread, so relying on it isn't an - * option in almost all cases... - * b) use random qID, based on some random-number generation mechanism. - * This way, we increase our protection a bit (see above - it's very weak - * still), but we also increase risk of qID reuse and matching late replies - * that comes to queries we've sent before against new queries. There are - * some more corner cases around that, as well - for example, normally, - * udns tries to find the query for a given reply by qID, *and* by - * verifying that the query DN and other parameters are also the same - * (so if the new query is against another domain name, old reply will - * be ignored automatically). But certain types of replies which we now - * handle - for example, FORMERR reply from servers which refuses to - * process EDNS0-enabled packets - comes without all the query parameters - * but the qID - so we're forced to use qID only when determining which - * query the given reply corresponds to. This makes us even more - * vulnerable to spoofing attacks, because an attacker don't even need to - * know which queries we perform to spoof the replies - he only needs to - * flood us with fake FORMERR "replies". - * - * That all to say: using sequential (or any other trivially guessable) - * numbers for qIDs is insecure, but the whole thing is inherently insecure - * as well, and this "extra weakness" that comes from weak qID choosing - * algorithm adds almost nothing to the underlying problem. - * - * It CAN NOT be made secure. Period. That's it. - * Unless we choose to implement DNSSEC, which is a whole different story. - * Forcing TCP mode makes it better, but who uses TCP for DNS anyway? - * (and it's hardly possible because of huge impact on the recursive - * nameservers). - * - * Note that ALL stub resolvers (again, unless they implement and enforce - * DNSSEC) suffers from this same problem. - * - * So, instead of trying to be more secure (which actually is not - false - * sense of security is - I think - is worse than no security), I'm trying - * to be more robust here (by preventing qID reuse, which helps in normal - * conditions). And use sequential qID generation scheme. - */ - dns_put16(q->dnsq_id, ctx->dnsc_nextid++); - /* reset all parameters relevant for previous query lifetime */ - q->dnsq_try = 0; - q->dnsq_servi = 0; - /*XXX probably should keep dnsq_servnEDNS0 bits? - * See also comments in dns_ioevent() about FORMERR case */ - q->dnsq_servwait = q->dnsq_servskip = q->dnsq_servnEDNS0 = 0; -} - -/* Find next search suffix and fills in q->dnsq_dn. - * Return 0 if no more to try. */ -static int dns_next_srch(struct dns_ctx *ctx, struct dns_query *q) { - unsigned dnl; - - for(;;) { - if (q->dnsq_nxtsrch > ctx->dnsc_srchend) - return 0; - dnl = dns_dnlen(q->dnsq_nxtsrch); - if (dnl + q->dnsq_origdnl0 <= DNS_MAXDN && - (*q->dnsq_nxtsrch || !(q->dnsq_flags & DNS_ASIS_DONE))) - break; - q->dnsq_nxtsrch += dnl; - } - memcpy(q->dnsq_dn + q->dnsq_origdnl0, q->dnsq_nxtsrch, dnl); - if (!*q->dnsq_nxtsrch) - q->dnsq_flags |= DNS_ASIS_DONE; - q->dnsq_nxtsrch += dnl; - dns_newid(ctx, q); /* new ID for new qDN */ - return 1; -} - -/* find the server to try for current iteration. - * Note that current dnsq_servi may point to a server we should skip -- - * in that case advance to the next server. - * Return true if found, false if all tried. - */ -static int dns_find_serv(const struct dns_ctx *ctx, struct dns_query *q) { - while(q->dnsq_servi < ctx->dnsc_nserv) { - if (!(q->dnsq_servskip & (1 << q->dnsq_servi))) - return 1; - ++q->dnsq_servi; - } - return 0; -} - -/* format and send the query to a given server. - * In case of network problem (sendto() fails), return -1, - * else return 0. - */ -static int -dns_send_this(struct dns_ctx *ctx, struct dns_query *q, - unsigned servi, time_t now) { - unsigned qlen; - unsigned tries; - - { /* format the query buffer */ - dnsc_t *p = ctx->dnsc_pbuf; - memset(p, 0, DNS_HSIZE); - if (!(q->dnsq_flags & DNS_NORD)) p[DNS_H_F1] |= DNS_HF1_RD; - if (q->dnsq_flags & DNS_AAONLY) p[DNS_H_F1] |= DNS_HF1_AA; - p[DNS_H_QDCNT2] = 1; - memcpy(p + DNS_H_QID, q->dnsq_id, 2); - p = dns_payload(p); - /* copy query dn */ - p += dns_dntodn(q->dnsq_dn, p, DNS_MAXDN); - /* query type and class */ - memcpy(p, q->dnsq_typcls, 4); p += 4; - /* add EDNS0 size record */ - if (ctx->dnsc_udpbuf > DNS_MAXPACKET && - !(q->dnsq_servnEDNS0 & (1 << servi))) { - *p++ = 0; /* empty (root) DN */ - p = dns_put16(p, DNS_T_OPT); - p = dns_put16(p, ctx->dnsc_udpbuf); - /* EDNS0 RCODE & VERSION; rest of the TTL field; RDLEN */ - memset(p, 0, 2+2+2); p += 2+2+2; - ctx->dnsc_pbuf[DNS_H_ARCNT2] = 1; - } - qlen = p - ctx->dnsc_pbuf; - assert(qlen <= ctx->dnsc_udpbuf); - } - - /* send the query */ - tries = 10; - while (sendto(ctx->dnsc_udpsock, (void*)ctx->dnsc_pbuf, qlen, 0, - &ctx->dnsc_serv[servi].sa, ctx->dnsc_salen) < 0) { - /*XXX just ignore the sendto() error for now and try again. - * In the future, it may be possible to retrieve the error code - * and find which operation/query failed. - *XXX try the next server too? (if ENETUNREACH is returned immediately) - */ - if (--tries) continue; - /* if we can't send the query, fail it. */ - dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0); - return -1; - } - DNS_DBGQ(ctx, q, 1, - &ctx->dnsc_serv[servi].sa, sizeof(union sockaddr_ns), - ctx->dnsc_pbuf, qlen); - q->dnsq_servwait |= 1 << servi; /* expect reply from this ns */ - - q->dnsq_deadline = now + - (dns_find_serv(ctx, q) ? 1 : ctx->dnsc_timeout << q->dnsq_try); - - /* move the query to the proper place, according to the new deadline */ - qlist_remove(q); - { /* insert from the tail */ - struct dns_query *p; - QLIST_FOR_EACH(&ctx->dnsc_qactive, p, prev) - if (p->dnsq_deadline <= q->dnsq_deadline) - break; - qlist_insert_after(q, p); - } - - return 0; -} - -/* send the query out using next available server - * and add it to the active list, or, if no servers available, - * end it. - */ -static void -dns_send(struct dns_ctx *ctx, struct dns_query *q, time_t now) { - - /* if we can't send the query, return TEMPFAIL even when searching: - * we can't be sure whenever the name we tried to search exists or not, - * so don't continue searching, or we may find the wrong name. */ - - if (!dns_find_serv(ctx, q)) { - /* no more servers in this iteration. Try the next cycle */ - q->dnsq_servi = 0; /* reset */ - q->dnsq_try++; /* next try */ - if (q->dnsq_try >= ctx->dnsc_ntries || - !dns_find_serv(ctx, q)) { - /* no more servers and tries, fail the query */ - /* return TEMPFAIL even when searching: no more tries for this - * searchlist, and no single definitive reply (handled in dns_ioevent() - * in NOERROR or NXDOMAIN cases) => all nameservers failed to process - * current search list element, so we don't know whenever the name exists. - */ - dns_end_query(ctx, q, DNS_E_TEMPFAIL, 0); - return; - } - } - - dns_send_this(ctx, q, q->dnsq_servi++, now); -} - -static void dns_dummy_cb(struct dns_ctx *ctx, void *result, void *data) { - if (result) free(result); - data = ctx = 0; /* used */ -} - -/* The (only, main, real) query submission routine. - * Allocate new query structure, initialize it, check validity of - * parameters, and add it to the head of the active list, without - * trying to send it (to be picked up on next event). - * Error return (without calling the callback routine) - - * no memory or wrong parameters. - *XXX The `no memory' case probably should go to the callback anyway... - */ -struct dns_query * -dns_submit_dn(struct dns_ctx *ctx, - dnscc_t *dn, int qcls, int qtyp, int flags, - dns_parse_fn *parse, dns_query_fn *cbck, void *data) { - struct dns_query *q; - SETCTXOPEN(ctx); - dns_assert_ctx(ctx); - - q = calloc(sizeof(*q), 1); - if (!q) { - ctx->dnsc_qstatus = DNS_E_NOMEM; - return NULL; - } - -#ifndef NDEBUG - q->dnsq_ctx = ctx; -#endif - q->dnsq_parse = parse; - q->dnsq_cbck = cbck ? cbck : dns_dummy_cb; - q->dnsq_cbdata = data; - - q->dnsq_origdnl0 = dns_dntodn(dn, q->dnsq_dn, sizeof(q->dnsq_dn)); - assert(q->dnsq_origdnl0 > 0); - --q->dnsq_origdnl0; /* w/o the trailing 0 */ - dns_put16(q->dnsq_typcls+0, qtyp); - dns_put16(q->dnsq_typcls+2, qcls); - q->dnsq_flags = (flags | ctx->dnsc_flags) & ~DNS_INTERNAL; - - if (flags & DNS_NOSRCH || - dns_dnlabels(q->dnsq_dn) > ctx->dnsc_ndots) { - q->dnsq_nxtsrch = flags & DNS_NOSRCH ? - ctx->dnsc_srchend /* end of the search list if no search requested */ : - ctx->dnsc_srchbuf /* beginning of the list, but try as-is first */; - q->dnsq_flags |= DNS_ASIS_DONE; - dns_newid(ctx, q); - } - else { - q->dnsq_nxtsrch = ctx->dnsc_srchbuf; - dns_next_srch(ctx, q); - } - - qlist_add_head(q, &ctx->dnsc_qactive); - ++ctx->dnsc_nactive; - dns_request_utm(ctx, 0); - - return q; -} - -struct dns_query * -dns_submit_p(struct dns_ctx *ctx, - const char *name, int qcls, int qtyp, int flags, - dns_parse_fn *parse, dns_query_fn *cbck, void *data) { - int isabs; - SETCTXOPEN(ctx); - if (dns_ptodn(name, 0, ctx->dnsc_pbuf, DNS_MAXDN, &isabs) <= 0) { - ctx->dnsc_qstatus = DNS_E_BADQUERY; - return NULL; - } - if (isabs) - flags |= DNS_NOSRCH; - return - dns_submit_dn(ctx, ctx->dnsc_pbuf, qcls, qtyp, flags, parse, cbck, data); -} - -/* process readable fd condition. - * To be usable in edge-triggered environment, the routine - * should consume all input so it should loop over. - * Note it isn't really necessary to loop here, because - * an application may perform the loop just fine by it's own, - * but in this case we should return some sensitive result, - * to indicate when to stop calling and error conditions. - * Note also we may encounter all sorts of recvfrom() - * errors which aren't fatal, and at the same time we may - * loop forever if an error IS fatal. - */ -void dns_ioevent(struct dns_ctx *ctx, time_t now) { - int r; - unsigned servi; - struct dns_query *q; - dnsc_t *pbuf; - dnscc_t *pend, *pcur; - void *result; - union sockaddr_ns sns; - socklen_t slen; - - SETCTX(ctx); - if (!CTXOPEN(ctx)) - return; - dns_assert_ctx(ctx); - pbuf = ctx->dnsc_pbuf; - - if (!now) now = time(NULL); - -again: /* receive the reply */ - - slen = sizeof(sns); - r = recvfrom(ctx->dnsc_udpsock, (void*)pbuf, ctx->dnsc_udpbuf, - MSG_DONTWAIT, &sns.sa, &slen); - if (r < 0) { - /*XXX just ignore recvfrom() errors for now. - * in the future it may be possible to determine which - * query failed and requeue it. - * Note there may be various error conditions, triggered - * by both local problems and remote problems. It isn't - * quite trivial to determine whenever an error is local - * or remote. On local errors, we should stop, while - * remote errors should be ignored (for now anyway). - */ -#ifdef WINDOWS - if (WSAGetLastError() == WSAEWOULDBLOCK) -#else - if (errno == EAGAIN) -#endif - { - dns_request_utm(ctx, now); - return; - } - goto again; - } - - pend = pbuf + r; - pcur = dns_payload(pbuf); - - /* check reply header */ - if (pcur > pend || dns_numqd(pbuf) > 1 || dns_opcode(pbuf) != 0) { - DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r); - goto again; - } - - /* find the matching query, by qID */ - for (q = QLIST_FIRST(&ctx->dnsc_qactive, next);; q = QLIST_NEXT(q, next)) { - if (QLIST_ISLAST(&ctx->dnsc_qactive, q)) { - /* no more requests: old reply? */ - DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r); - goto again; - } - if (pbuf[DNS_H_QID1] == q->dnsq_id[0] && - pbuf[DNS_H_QID2] == q->dnsq_id[1]) - break; - } - - /* if we have numqd, compare with our query qDN */ - if (dns_numqd(pbuf)) { - /* decode the qDN */ - dnsc_t dn[DNS_MAXDN]; - if (dns_getdn(pbuf, &pcur, pend, dn, sizeof(dn)) < 0 || - pcur + 4 > pend) { - DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r); - goto again; - } - if (!dns_dnequal(dn, q->dnsq_dn) || - memcmp(pcur, q->dnsq_typcls, 4) != 0) { - /* not this query */ - DNS_DBG(ctx, -5/*no matching query*/, &sns.sa, slen, pbuf, r); - goto again; - } - /* here, query match, and pcur points past qDN in query section in pbuf */ - } - /* if no numqd, we only allow FORMERR rcode */ - else if (dns_rcode(pbuf) != DNS_R_FORMERR) { - /* treat it as bad reply if !FORMERR */ - DNS_DBG(ctx, -1/*bad reply*/, &sns.sa, slen, pbuf, r); - goto again; - } - else { - /* else it's FORMERR, handled below */ - } - - /* find server */ -#ifdef HAVE_IPv6 - if (sns.sa.sa_family == AF_INET6 && slen >= sizeof(sns.sin6)) { - for(servi = 0; servi < ctx->dnsc_nserv; ++servi) - if (sin6_eq(ctx->dnsc_serv[servi].sin6, sns.sin6)) - break; - } - else -#endif - if (sns.sa.sa_family == AF_INET && slen >= sizeof(sns.sin)) { - for(servi = 0; servi < ctx->dnsc_nserv; ++servi) - if (sin_eq(ctx->dnsc_serv[servi].sin, sns.sin)) - break; - } - else - servi = ctx->dnsc_nserv; - - /* check if we expect reply from this server. - * Note we can receive reply from first try if we're already at next */ - if (!(q->dnsq_servwait & (1 << servi))) { /* if ever asked this NS */ - DNS_DBG(ctx, -2/*wrong server*/, &sns.sa, slen, pbuf, r); - goto again; - } - - /* we got (some) reply for our query */ - - DNS_DBGQ(ctx, q, 0, &sns.sa, slen, pbuf, r); - q->dnsq_servwait &= ~(1 << servi); /* don't expect reply from this serv */ - - /* process the RCODE */ - switch(dns_rcode(pbuf)) { - - case DNS_R_NOERROR: - if (dns_tc(pbuf)) { - /* possible truncation. We can't deal with it. */ - /*XXX for now, treat TC bit the same as SERVFAIL. - * It is possible to: - * a) try to decode the reply - may be ANSWER section is ok; - * b) check if server understands EDNS0, and if it is, and - * answer still don't fit, end query. - */ - break; - } - if (!dns_numan(pbuf)) { /* no data of requested type */ - if (dns_next_srch(ctx, q)) { - /* if we're searching, try next searchlist element, - * but remember NODATA reply. */ - q->dnsq_flags |= DNS_SEEN_NODATA; - dns_send(ctx, q, now); - } - else - /* else - nothing to search any more - finish the query. - * It will be NODATA since we've seen a NODATA reply. */ - dns_end_query(ctx, q, DNS_E_NODATA, 0); - } - /* we've got a positive reply here */ - else if (q->dnsq_parse) { - /* if we have parsing routine, call it and return whatever it returned */ - /* don't try to re-search if NODATA here. For example, - * if we asked for A but only received CNAME. Unless we'll - * someday do recursive queries. And that's problematic too, since - * we may be dealing with specific AA-only nameservers for a given - * domain, but CNAME points elsewhere... - */ - r = q->dnsq_parse(q->dnsq_dn, pbuf, pcur, pend, &result); - dns_end_query(ctx, q, r, r < 0 ? NULL : result); - } - /* else just malloc+copy the raw DNS reply */ - else if ((result = malloc(r)) == NULL) - dns_end_query(ctx, q, DNS_E_NOMEM, NULL); - else { - memcpy(result, pbuf, r); - dns_end_query(ctx, q, r, result); - } - goto again; - - case DNS_R_NXDOMAIN: /* Non-existing domain. */ - if (dns_next_srch(ctx, q)) - /* more search entries exists, try them. */ - dns_send(ctx, q, now); - else - /* nothing to search anymore. End the query, returning either NODATA - * if we've seen it before, or NXDOMAIN if not. */ - dns_end_query(ctx, q, - q->dnsq_flags & DNS_SEEN_NODATA ? DNS_E_NODATA : DNS_E_NXDOMAIN, 0); - goto again; - - case DNS_R_FORMERR: - case DNS_R_NOTIMPL: - /* for FORMERR and NOTIMPL rcodes, if we tried EDNS0-enabled query, - * try w/o EDNS0. */ - if (ctx->dnsc_udpbuf > DNS_MAXPACKET && - !(q->dnsq_servnEDNS0 & (1 << servi))) { - /* we always trying EDNS0 first if enabled, and retry a given query - * if not available. Maybe it's better to remember inavailability of - * EDNS0 in ctx as a per-NS flag, and never try again for this NS. - * For long-running applications.. maybe they will change the nameserver - * while we're running? :) Also, since FORMERR is the only rcode we - * allow to be header-only, and in this case the only check we do to - * find a query it belongs to is qID (not qDN+qCLS+qTYP), it's much - * easier to spoof and to force us to perform non-EDNS0 queries only... - */ - q->dnsq_servnEDNS0 |= 1 << servi; - dns_send_this(ctx, q, servi, now); - goto again; - } - /* else we handle it the same as SERVFAIL etc */ - - case DNS_R_SERVFAIL: - case DNS_R_REFUSED: - /* for these rcodes, advance this request - * to the next server and reschedule */ - default: /* unknown rcode? hmmm... */ - break; - } - - /* here, we received unexpected reply */ - q->dnsq_servskip |= (1 << servi); /* don't retry this server */ - - /* we don't expect replies from this server anymore. - * But there may be other servers. Some may be still processing our - * query, and some may be left to try. - * We just ignore this reply and wait a bit more if some NSes haven't - * replied yet (dnsq_servwait != 0), and let the situation to be handled - * on next event processing. Timeout for this query is set correctly, - * if not taking into account the one-second difference - we can try - * next server in the same iteration sooner. - */ - - /* try next server */ - if (!q->dnsq_servwait) { - /* next retry: maybe some other servers will reply next time. - * dns_send() will end the query for us if no more servers to try. - * Note we can't continue with the next searchlist element here: - * we don't know if the current qdn exists or not, there's no definitive - * answer yet (which is seen in cases above). - *XXX standard resolver also tries as-is query in case all nameservers - * failed to process our query and if not tried before. We don't do it. - */ - dns_send(ctx, q, now); - } - else { - /* else don't do anything - not all servers replied yet */ - } - goto again; - -} - -/* handle all timeouts */ -int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now) { - /* this is a hot routine */ - struct dns_query *q; - - SETCTX(ctx); - dns_assert_ctx(ctx); - - /* Pick up first entry from query list. - * If its deadline has passed, (re)send it - * (dns_send() will move it next in the list). - * If not, this is the query which determines the closest deadline. - */ - - q = qlist_first(&ctx->dnsc_qactive); - if (!q) - return maxwait; - if (!now) - now = time(NULL); - do { - if (q->dnsq_deadline > now) { /* first non-expired query */ - int w = (int)(q->dnsq_deadline - now); - if (maxwait < 0 || maxwait > w) - maxwait = w; - break; - } - else { - /* process expired deadline */ - dns_send(ctx, q, now); - } - } while((q = qlist_first(&ctx->dnsc_qactive)) != NULL); - - dns_request_utm(ctx, now); /* update timer with new deadline */ - return maxwait; -} - -struct dns_resolve_data { - int dnsrd_done; - void *dnsrd_result; -}; - -static void dns_resolve_cb(struct dns_ctx *ctx, void *result, void *data) { - struct dns_resolve_data *d = data; - d->dnsrd_result = result; - d->dnsrd_done = 1; - ctx = ctx; -} - -void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) { - time_t now; - struct dns_resolve_data d; - int n; - SETCTXOPEN(ctx); - - if (!q) - return NULL; - - assert(ctx == q->dnsq_ctx); - dns_assert_ctx(ctx); - /* do not allow re-resolving syncronous queries */ - assert(q->dnsq_cbck != dns_resolve_cb && "can't resolve syncronous query"); - if (q->dnsq_cbck == dns_resolve_cb) { - ctx->dnsc_qstatus = DNS_E_BADQUERY; - return NULL; - } - q->dnsq_cbck = dns_resolve_cb; - q->dnsq_cbdata = &d; - d.dnsrd_done = 0; - - now = time(NULL); - while(!d.dnsrd_done && (n = dns_timeouts(ctx, -1, now)) >= 0) { -#ifdef HAVE_POLL - struct pollfd pfd; - pfd.fd = ctx->dnsc_udpsock; - pfd.events = POLLIN; - n = poll(&pfd, 1, n * 1000); -#else - fd_set rfd; - struct timeval tv; - FD_ZERO(&rfd); - FD_SET(ctx->dnsc_udpsock, &rfd); - tv.tv_sec = n; tv.tv_usec = 0; - n = select(ctx->dnsc_udpsock + 1, &rfd, NULL, NULL, &tv); -#endif - now = time(NULL); - if (n > 0) - dns_ioevent(ctx, now); - } - - return d.dnsrd_result; -} - -void *dns_resolve_dn(struct dns_ctx *ctx, - dnscc_t *dn, int qcls, int qtyp, int flags, - dns_parse_fn *parse) { - return - dns_resolve(ctx, - dns_submit_dn(ctx, dn, qcls, qtyp, flags, parse, NULL, NULL)); -} - -void *dns_resolve_p(struct dns_ctx *ctx, - const char *name, int qcls, int qtyp, int flags, - dns_parse_fn *parse) { - return - dns_resolve(ctx, - dns_submit_p(ctx, name, qcls, qtyp, flags, parse, NULL, NULL)); -} - -int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) { - SETCTX(ctx); - dns_assert_ctx(ctx); - assert(q->dnsq_ctx == ctx); - /* do not allow cancelling syncronous queries */ - assert(q->dnsq_cbck != dns_resolve_cb && "can't cancel syncronous query"); - if (q->dnsq_cbck == dns_resolve_cb) - return (ctx->dnsc_qstatus = DNS_E_BADQUERY); - qlist_remove(q); - --ctx->dnsc_nactive; - dns_request_utm(ctx, 0); - return 0; -} - diff --git a/deps/udns/udns_rr_a.c b/deps/udns/udns_rr_a.c deleted file mode 100644 index ca99dfe91c0..00000000000 --- a/deps/udns/udns_rr_a.c +++ /dev/null @@ -1,123 +0,0 @@ -/* $Id: udns_rr_a.c,v 1.16 2007/01/09 04:44:51 mjt Exp $ - parse/query A/AAAA IN records - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include -#ifndef WINDOWS -# include -# include -#endif -#include "udns.h" - -/* here, we use common routine to parse both IPv4 and IPv6 addresses. - */ - -/* this structure should match dns_rr_a[46] */ -struct dns_rr_a { - dns_rr_common(dnsa); - unsigned char *dnsa_addr; -}; - -static int -dns_parse_a(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result, unsigned dsize) { - struct dns_rr_a *ret; - struct dns_parse p; - struct dns_rr rr; - int r; - - /* first, validate and count number of addresses */ - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) - if (rr.dnsrr_dsz != dsize) - return DNS_E_PROTOCOL; - if (r < 0) - return DNS_E_PROTOCOL; - else if (!p.dnsp_nrr) - return DNS_E_NODATA; - - ret = malloc(sizeof(*ret) + dsize * p.dnsp_nrr + dns_stdrr_size(&p)); - if (!ret) - return DNS_E_NOMEM; - - ret->dnsa_nrr = p.dnsp_nrr; - ret->dnsa_addr = (unsigned char*)(ret+1); - - /* copy the RRs */ - for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) - memcpy(ret->dnsa_addr + dsize * r, rr.dnsrr_dptr, dsize); - - dns_stdrr_finish((struct dns_rr_null *)ret, - (char *)(ret->dnsa_addr + dsize * p.dnsp_nrr), &p); - *result = ret; - return 0; -} - -int -dns_parse_a4(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { -#ifdef AF_INET - assert(sizeof(struct in_addr) == 4); -#endif - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_A); - return dns_parse_a(qdn, pkt, cur, end, result, 4); -} - -struct dns_query * -dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags, - dns_query_a4_fn *cbck, void *data) { - return - dns_submit_p(ctx, name, DNS_C_IN, DNS_T_A, flags, - dns_parse_a4, (dns_query_fn*)cbck, data); -} - -struct dns_rr_a4 * -dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags) { - return (struct dns_rr_a4 *) - dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_A, flags, dns_parse_a4); -} - -int -dns_parse_a6(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { -#ifdef AF_INET6 - assert(sizeof(struct in6_addr) == 16); -#endif - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_AAAA); - return dns_parse_a(qdn, pkt, cur, end, result, 16); -} - -struct dns_query * -dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags, - dns_query_a6_fn *cbck, void *data) { - return - dns_submit_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, - dns_parse_a6, (dns_query_fn*)cbck, data); -} - -struct dns_rr_a6 * -dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags) { - return (struct dns_rr_a6 *) - dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, dns_parse_a6); -} diff --git a/deps/udns/udns_rr_mx.c b/deps/udns/udns_rr_mx.c deleted file mode 100644 index cf8348354f6..00000000000 --- a/deps/udns/udns_rr_mx.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $Id: udns_rr_mx.c,v 1.13 2005/04/20 06:44:34 mjt Exp $ - parse/query MX IN records - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include -#include "udns.h" - -int -dns_parse_mx(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { - struct dns_rr_mx *ret; - struct dns_parse p; - struct dns_rr rr; - int r, l; - char *sp; - dnsc_t mx[DNS_MAXDN]; - - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_MX); - - /* first, validate the answer and count size of the result */ - l = 0; - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) { - cur = rr.dnsrr_dptr + 2; - r = dns_getdn(pkt, &cur, end, mx, sizeof(mx)); - if (r <= 0 || cur != rr.dnsrr_dend) - return DNS_E_PROTOCOL; - l += dns_dntop_size(mx); - } - if (r < 0) - return DNS_E_PROTOCOL; - if (!p.dnsp_nrr) - return DNS_E_NODATA; - - /* next, allocate and set up result */ - l += dns_stdrr_size(&p); - ret = malloc(sizeof(*ret) + sizeof(struct dns_mx) * p.dnsp_nrr + l); - if (!ret) - return DNS_E_NOMEM; - ret->dnsmx_nrr = p.dnsp_nrr; - ret->dnsmx_mx = (struct dns_mx *)(ret+1); - - /* and 3rd, fill in result, finally */ - sp = (char*)(ret->dnsmx_mx + p.dnsp_nrr); - for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { - ret->dnsmx_mx[r].name = sp; - cur = rr.dnsrr_dptr; - ret->dnsmx_mx[r].priority = dns_get16(cur); - cur += 2; - dns_getdn(pkt, &cur, end, mx, sizeof(mx)); - sp += dns_dntop(mx, sp, DNS_MAXNAME); - } - dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); - *result = ret; - return 0; -} - -struct dns_query * -dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags, - dns_query_mx_fn *cbck, void *data) { - return - dns_submit_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, - dns_parse_mx, (dns_query_fn *)cbck, data); -} - -struct dns_rr_mx * -dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags) { - return (struct dns_rr_mx *) - dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, dns_parse_mx); -} diff --git a/deps/udns/udns_rr_naptr.c b/deps/udns/udns_rr_naptr.c deleted file mode 100644 index ec4f5146010..00000000000 --- a/deps/udns/udns_rr_naptr.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id: udns_rr_naptr.c,v 1.1 2006/11/28 22:58:04 mjt Exp $ - parse/query NAPTR IN records - - Copyright (C) 2005 Michael Tokarev - Copyright (C) 2006 Mikael Magnusson - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include -#include "udns.h" - -/* Get a single string for NAPTR record, pretty much like a DN label. - * String length is in first byte in *cur, so it can't be >255. - */ -static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf) -{ - unsigned l; - dnscc_t *cp = *cur; - - l = *cp++; - if (cp + l > ep) - return DNS_E_PROTOCOL; - if (buf) { - memcpy(buf, cp, l); - buf[l] = '\0'; - } - cp += l; - - *cur = cp; - return l + 1; -} - -int -dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { - struct dns_rr_naptr *ret; - struct dns_parse p; - struct dns_rr rr; - int r, l; - char *sp; - dnsc_t dn[DNS_MAXDN]; - - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR); - - /* first, validate the answer and count size of the result */ - l = 0; - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) { - int i; - dnscc_t *ep = rr.dnsrr_dend; - - /* first 4 bytes: order & preference */ - cur = rr.dnsrr_dptr + 4; - - /* flags, services and regexp */ - for (i = 0; i < 3; i++) { - r = dns_getstr(&cur, ep, NULL); - if (r < 0) - return r; - l += r; - } - /* replacement */ - r = dns_getdn(pkt, &cur, end, dn, sizeof(dn)); - if (r <= 0 || cur != rr.dnsrr_dend) - return DNS_E_PROTOCOL; - l += dns_dntop_size(dn); - } - if (r < 0) - return DNS_E_PROTOCOL; - if (!p.dnsp_nrr) - return DNS_E_NODATA; - - /* next, allocate and set up result */ - l += dns_stdrr_size(&p); - ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l); - if (!ret) - return DNS_E_NOMEM; - ret->dnsnaptr_nrr = p.dnsp_nrr; - ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1); - - /* and 3rd, fill in result, finally */ - sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]); - for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { - cur = rr.dnsrr_dptr; - ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2; - ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2; - sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp)); - sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp)); - sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp)); - dns_getdn(pkt, &cur, end, dn, sizeof(dn)); - sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME); - } - dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); - *result = ret; - return 0; -} - -struct dns_query * -dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags, - dns_query_naptr_fn *cbck, void *data) { - return - dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, - dns_parse_naptr, (dns_query_fn *)cbck, data); -} - -struct dns_rr_naptr * -dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) { - return (struct dns_rr_naptr *) - dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr); -} diff --git a/deps/udns/udns_rr_ptr.c b/deps/udns/udns_rr_ptr.c deleted file mode 100644 index 410af656a55..00000000000 --- a/deps/udns/udns_rr_ptr.c +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id: udns_rr_ptr.c,v 1.15 2005/09/12 11:21:06 mjt Exp $ - parse/query PTR records - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include "udns.h" - -int -dns_parse_ptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { - struct dns_rr_ptr *ret; - struct dns_parse p; - struct dns_rr rr; - int r, l, c; - char *sp; - dnsc_t ptr[DNS_MAXDN]; - - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_PTR); - - /* first, validate the answer and count size of the result */ - l = c = 0; - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) { - cur = rr.dnsrr_dptr; - r = dns_getdn(pkt, &cur, end, ptr, sizeof(ptr)); - if (r <= 0 || cur != rr.dnsrr_dend) - return DNS_E_PROTOCOL; - l += dns_dntop_size(ptr); - ++c; - } - if (r < 0) - return DNS_E_PROTOCOL; - if (!c) - return DNS_E_NODATA; - - /* next, allocate and set up result */ - ret = malloc(sizeof(*ret) + sizeof(char **) * c + l + dns_stdrr_size(&p)); - if (!ret) - return DNS_E_NOMEM; - ret->dnsptr_nrr = c; - ret->dnsptr_ptr = (char **)(ret+1); - - /* and 3rd, fill in result, finally */ - sp = (char*)(ret->dnsptr_ptr + c); - c = 0; - dns_rewind(&p, qdn); - while((r = dns_nextrr(&p, &rr)) > 0) { - ret->dnsptr_ptr[c] = sp; - cur = rr.dnsrr_dptr; - dns_getdn(pkt, &cur, end, ptr, sizeof(ptr)); - sp += dns_dntop(ptr, sp, DNS_MAXNAME); - ++c; - } - dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); - *result = ret; - return 0; -} - -struct dns_query * -dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr, - dns_query_ptr_fn *cbck, void *data) { - dnsc_t dn[DNS_A4RSIZE]; - dns_a4todn(addr, 0, dn, sizeof(dn)); - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH, - dns_parse_ptr, (dns_query_fn *)cbck, data); -} - -struct dns_rr_ptr * -dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr) { - return (struct dns_rr_ptr *) - dns_resolve(ctx, dns_submit_a4ptr(ctx, addr, NULL, NULL)); -} - -struct dns_query * -dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr, - dns_query_ptr_fn *cbck, void *data) { - dnsc_t dn[DNS_A6RSIZE]; - dns_a6todn(addr, 0, dn, sizeof(dn)); - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH, - dns_parse_ptr, (dns_query_fn *)cbck, data); -} - -struct dns_rr_ptr * -dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr) { - return (struct dns_rr_ptr *) - dns_resolve(ctx, dns_submit_a6ptr(ctx, addr, NULL, NULL)); -} diff --git a/deps/udns/udns_rr_srv.c b/deps/udns/udns_rr_srv.c deleted file mode 100644 index 56bbbf7f786..00000000000 --- a/deps/udns/udns_rr_srv.c +++ /dev/null @@ -1,154 +0,0 @@ -/* $Id: udns_rr_srv.c,v 1.2 2005/09/12 12:26:22 mjt Exp $ - parse/query SRV IN (rfc2782) records - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - Copyright 2005 Thadeu Lima de Souza Cascardo - - 2005-09-11: - Changed MX parser file into a SRV parser file - - */ - -#include -#include -#include -#include "udns.h" - -int -dns_parse_srv(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { - struct dns_rr_srv *ret; - struct dns_parse p; - struct dns_rr rr; - int r, l; - char *sp; - dnsc_t srv[DNS_MAXDN]; - - assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_SRV); - - /* first, validate the answer and count size of the result */ - l = 0; - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) { - cur = rr.dnsrr_dptr + 6; - r = dns_getdn(pkt, &cur, end, srv, sizeof(srv)); - if (r <= 0 || cur != rr.dnsrr_dend) - return DNS_E_PROTOCOL; - l += dns_dntop_size(srv); - } - if (r < 0) - return DNS_E_PROTOCOL; - if (!p.dnsp_nrr) - return DNS_E_NODATA; - - /* next, allocate and set up result */ - l += dns_stdrr_size(&p); - ret = malloc(sizeof(*ret) + sizeof(struct dns_srv) * p.dnsp_nrr + l); - if (!ret) - return DNS_E_NOMEM; - ret->dnssrv_nrr = p.dnsp_nrr; - ret->dnssrv_srv = (struct dns_srv *)(ret+1); - - /* and 3rd, fill in result, finally */ - sp = (char*)(ret->dnssrv_srv + p.dnsp_nrr); - for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { - ret->dnssrv_srv[r].name = sp; - cur = rr.dnsrr_dptr; - ret->dnssrv_srv[r].priority = dns_get16(cur); - ret->dnssrv_srv[r].weight = dns_get16(cur+2); - ret->dnssrv_srv[r].port = dns_get16(cur+4); - cur += 6; - dns_getdn(pkt, &cur, end, srv, sizeof(srv)); - sp += dns_dntop(srv, sp, DNS_MAXNAME); - } - dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); - *result = ret; - return 0; -} - -/* Add a single service or proto name prepending an undescore (_), - * according to rfc2782 rules. - * Return 0 or the label length. - * Routing assumes dn holds enouth space for a single DN label. */ -static unsigned add_sname(dnsc_t *dn, const char *sn) { - unsigned l; - l = dns_ptodn(sn, 0, dn + 1, DNS_MAXLABEL-1, NULL); - if (l <= 1 || l - 2 != dn[1]) - /* Should we really check if sn is exactly one label? Do we care? */ - return 0; - dn[0] = l - 1; - dn[1] = '_'; - return l; -} - -/* Construct a domain name for SRV query from the given name, service and - * protocol (service may be NULL in which case protocol isn't used). - * Return negative value on error (malformed query), - * or addition query flag(s) to use. - */ -static int -build_srv_dn(dnsc_t *dn, const char *name, const char *srv, const char *proto) -{ - unsigned p = 0, l; - int isabs; - if (srv) { - l = add_sname(dn + p, srv); - if (!l) - return -1; - p += l; - l = add_sname(dn + p, proto); - if (!l) - return -1; - p += l; - } - l = dns_ptodn(name, 0, dn + p, DNS_MAXDN - p, &isabs); - if (!l) - return -1; - return isabs ? DNS_NOSRCH : 0; -} - -struct dns_query * -dns_submit_srv(struct dns_ctx *ctx, - const char *name, const char *srv, const char *proto, - int flags, dns_query_srv_fn *cbck, void *data) { - dnsc_t dn[DNS_MAXDN]; - int r = build_srv_dn(dn, name, srv, proto); - if (r < 0) { - dns_setstatus (ctx, DNS_E_BADQUERY); - return NULL; - } - return - dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, - dns_parse_srv, (dns_query_fn *)cbck, data); -} - -struct dns_rr_srv * -dns_resolve_srv(struct dns_ctx *ctx, - const char *name, const char *srv, const char *proto, int flags) -{ - dnsc_t dn[DNS_MAXDN]; - int r = build_srv_dn(dn, name, srv, proto); - if (r < 0) { - dns_setstatus(ctx, DNS_E_BADQUERY); - return NULL; - } - return (struct dns_rr_srv *) - dns_resolve_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, dns_parse_srv); -} diff --git a/deps/udns/udns_rr_txt.c b/deps/udns/udns_rr_txt.c deleted file mode 100644 index ecc71f06ed8..00000000000 --- a/deps/udns/udns_rr_txt.c +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id: udns_rr_txt.c,v 1.15 2006/11/28 22:45:20 mjt Exp $ - parse/query TXT records - - Copyright (C) 2005 Michael Tokarev - This file is part of UDNS library, an async DNS stub resolver. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library, in file named COPYING.LGPL; if not, - write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA - - */ - -#include -#include -#include -#include "udns.h" - -int -dns_parse_txt(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, - void **result) { - struct dns_rr_txt *ret; - struct dns_parse p; - struct dns_rr rr; - int r, l; - dnsc_t *sp; - dnscc_t *cp, *ep; - - assert(dns_get16(cur+0) == DNS_T_TXT); - - /* first, validate the answer and count size of the result */ - l = 0; - dns_initparse(&p, qdn, pkt, cur, end); - while((r = dns_nextrr(&p, &rr)) > 0) { - cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend; - while(cp < ep) { - r = *cp++; - if (cp + r > ep) - return DNS_E_PROTOCOL; - l += r; - cp += r; - } - } - if (r < 0) - return DNS_E_PROTOCOL; - if (!p.dnsp_nrr) - return DNS_E_NODATA; - - /* next, allocate and set up result */ - l += (sizeof(struct dns_txt) + 1) * p.dnsp_nrr + dns_stdrr_size(&p); - ret = malloc(sizeof(*ret) + l); - if (!ret) - return DNS_E_NOMEM; - ret->dnstxt_nrr = p.dnsp_nrr; - ret->dnstxt_txt = (struct dns_txt *)(ret+1); - - /* and 3rd, fill in result, finally */ - sp = (dnsc_t*)(ret->dnstxt_txt + p.dnsp_nrr); - for(dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr) > 0; ++r) { - ret->dnstxt_txt[r].txt = sp; - cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend; - while(cp < ep) { - l = *cp++; - memcpy(sp, cp, l); - sp += l; - cp += l; - } - ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt; - *sp++ = '\0'; - } - dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p); - *result = ret; - return 0; -} - -struct dns_query * -dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags, - dns_query_txt_fn *cbck, void *data) { - return - dns_submit_p(ctx, name, qcls, DNS_T_TXT, flags, - dns_parse_txt, (dns_query_fn *)cbck, data); -} - -struct dns_rr_txt * -dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags) { - return (struct dns_rr_txt *) - dns_resolve_p(ctx, name, qcls, DNS_T_TXT, flags, dns_parse_txt); -} diff --git a/lib/dns.js b/lib/dns.js index cd7bc817d39..6794ef426f1 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -1,4 +1,72 @@ -var dns = process.binding('dns'); +var dns = process.binding('cares'); + + +var watchers = {}; +var activeWatchers = {}; + + +var timer = new process.Timer(); + +timer.callback = function () { + for (var socket in activeWatchers) { + var s = parseInt(socket); + channel.processFD( watchers[socket].read ? s : dns.SOCKET_BAD + , watchers[socket].write ? s : dns.SOCKET_BAD + ); + } + updateTimer(); +} + + +function updateTimer() { + timer.stop(); + + for (var socket in activeWatchers) { // if !empty(activeWatchers) + var max = 20000; + var timeout = channel.timeout(max); + + timer.start(timeout, 0); + + return; + } +} + + +var channel = new dns.Channel({SOCK_STATE_CB: function (socket, read, write) { + var watcher; + + if (socket in watchers) { + watcher = watchers[socket].watcher; + } else { + watcher = new process.IOWatcher(); + watchers[socket] = { read: read + , write: write + , watcher: watcher + }; + + watcher.callback = function(read, write) { + channel.processFD( read ? socket : dns.SOCKET_BAD + , write ? socket : dns.SOCKET_BAD + ); + updateTimer(); + } + } + + watcher.set(socket, read == 1, write == 1); + + if (!(read || write)) { + watcher.stop(); + delete activeWatchers[socket]; + return; + } else { + watcher.start(); + activeWatchers[socket] = watcher; + } + + updateTimer(); +}}); + + exports.resolve = function (domain, type_, callback_) { var type, callback; @@ -19,38 +87,64 @@ exports.resolve = function (domain, type_, callback_) { } } -exports.resolve4 = dns.resolve4; -exports.resolve6 = dns.resolve6; -exports.resolveMx = dns.resolveMx; -exports.resolveTxt = dns.resolveTxt; -exports.resolveSrv = dns.resolveSrv; -exports.reverse = dns.reverse; -// ERROR CODES +exports.getHostByName = function (domain, callback) { + channel.getHostByName(domain, dns.AF_INET, callback); +}; -// timeout, SERVFAIL or similar. -exports.TEMPFAIL = dns.TEMPFAIL; +// Easy DNS A/AAAA look up +exports.lookup = function (domain, callback) { + var addressType = dns.isIP(domain); + if (addressType) { + process.nextTick(function () { + callback(null, domain, addressType); + }); + } else { + channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { + if (domains4 && domains4.length) { + callback(null, domains4[0], 4); + } else { + channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { + if (domains6 && domains6.length) { + callback(null, domains6[0], 6); + } else { + callback(err, []); + } + }); + } + }); + } +}; -// got garbled reply. -exports.PROTOCOL = dns.PROTOCOL; -// domain does not exists. -exports.NXDOMAIN = dns.NXDOMAIN; +exports.resolve4 = function(domain, callback) { channel.query(domain, dns.A, callback) }; +exports.resolve6 = function(domain, callback) { channel.query(domain, dns.AAAA, callback) }; +exports.resolveTxt = function(domain, callback) { channel.query(domain, dns.TXT, callback) }; +exports.resolveSrv = function(domain, callback) { channel.query(domain, dns.SRV, callback) }; +exports.reverse = function(domain, callback) { channel.query(domain, dns.PTR, callback) }; +exports.resolveNs = function(domain, callback) { channel.query(domain, dns.NS, callback) }; -// domain exists but no data of reqd type. -exports.NODATA = dns.NODATA; - -// out of memory while processing. -exports.NOMEM = dns.NOMEM; - -// the query is malformed. -exports.BADQUERY = dns.BADQUERY; var resolveMap = { - 'A': exports.resolve4, + 'A' : exports.resolve4, 'AAAA': exports.resolve6, - 'MX': exports.resolveMx, - 'TXT': exports.resolveTxt, - 'SRV': exports.resolveSrv, - 'PTR': exports.reverse, + 'TXT' : exports.resolveTxt, + 'SRV' : exports.resolveSrv, + 'PTR' : exports.resolvePtr, + 'NS' : exports.resolveNs, }; + +// ERROR CODES +exports.NODATA = dns.NODATA; +exports.FORMERR = dns.FORMERR; +exports.BADRESP = dns.BADRESP; +exports.NOTFOUND = dns.NOTFOUND; +exports.BADNAME = dns.BADNAME; +exports.TIMEOUT = dns.TIMEOUT; +exports.CONNREFUSED = dns.CONNREFUSED; +exports.NOMEM = dns.NOMEM; +exports.DESTRUCTION = dns.DESTRUCTION; + +exports.NOTIMP = dns.NOTIMP; +exports.EREFUSED = dns.EREFUSED; +exports.SERVFAIL = dns.SERVFAIL; diff --git a/lib/dns_cares.js b/lib/dns_cares.js deleted file mode 100644 index 6794ef426f1..00000000000 --- a/lib/dns_cares.js +++ /dev/null @@ -1,150 +0,0 @@ -var dns = process.binding('cares'); - - -var watchers = {}; -var activeWatchers = {}; - - -var timer = new process.Timer(); - -timer.callback = function () { - for (var socket in activeWatchers) { - var s = parseInt(socket); - channel.processFD( watchers[socket].read ? s : dns.SOCKET_BAD - , watchers[socket].write ? s : dns.SOCKET_BAD - ); - } - updateTimer(); -} - - -function updateTimer() { - timer.stop(); - - for (var socket in activeWatchers) { // if !empty(activeWatchers) - var max = 20000; - var timeout = channel.timeout(max); - - timer.start(timeout, 0); - - return; - } -} - - -var channel = new dns.Channel({SOCK_STATE_CB: function (socket, read, write) { - var watcher; - - if (socket in watchers) { - watcher = watchers[socket].watcher; - } else { - watcher = new process.IOWatcher(); - watchers[socket] = { read: read - , write: write - , watcher: watcher - }; - - watcher.callback = function(read, write) { - channel.processFD( read ? socket : dns.SOCKET_BAD - , write ? socket : dns.SOCKET_BAD - ); - updateTimer(); - } - } - - watcher.set(socket, read == 1, write == 1); - - if (!(read || write)) { - watcher.stop(); - delete activeWatchers[socket]; - return; - } else { - watcher.start(); - activeWatchers[socket] = watcher; - } - - updateTimer(); -}}); - - - -exports.resolve = function (domain, type_, callback_) { - var type, callback; - if (typeof(type_) == 'string') { - type = type_; - callback = callback_; - } else { - type = 'A'; - callback = arguments[1]; - } - - var resolveFunc = resolveMap[type]; - - if (typeof(resolveFunc) == 'function') { - resolveFunc(domain, callback); - } else { - throw new Error('Unknown type "' + type + '"'); - } -} - - -exports.getHostByName = function (domain, callback) { - channel.getHostByName(domain, dns.AF_INET, callback); -}; - -// Easy DNS A/AAAA look up -exports.lookup = function (domain, callback) { - var addressType = dns.isIP(domain); - if (addressType) { - process.nextTick(function () { - callback(null, domain, addressType); - }); - } else { - channel.getHostByName(domain, dns.AF_INET, function (err, domains4) { - if (domains4 && domains4.length) { - callback(null, domains4[0], 4); - } else { - channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) { - if (domains6 && domains6.length) { - callback(null, domains6[0], 6); - } else { - callback(err, []); - } - }); - } - }); - } -}; - - -exports.resolve4 = function(domain, callback) { channel.query(domain, dns.A, callback) }; -exports.resolve6 = function(domain, callback) { channel.query(domain, dns.AAAA, callback) }; -exports.resolveTxt = function(domain, callback) { channel.query(domain, dns.TXT, callback) }; -exports.resolveSrv = function(domain, callback) { channel.query(domain, dns.SRV, callback) }; -exports.reverse = function(domain, callback) { channel.query(domain, dns.PTR, callback) }; -exports.resolveNs = function(domain, callback) { channel.query(domain, dns.NS, callback) }; - - -var resolveMap = { - 'A' : exports.resolve4, - 'AAAA': exports.resolve6, - 'TXT' : exports.resolveTxt, - 'SRV' : exports.resolveSrv, - 'PTR' : exports.resolvePtr, - 'NS' : exports.resolveNs, -}; - -// ERROR CODES -exports.NODATA = dns.NODATA; -exports.FORMERR = dns.FORMERR; -exports.BADRESP = dns.BADRESP; -exports.NOTFOUND = dns.NOTFOUND; -exports.BADNAME = dns.BADNAME; -exports.TIMEOUT = dns.TIMEOUT; -exports.CONNREFUSED = dns.CONNREFUSED; -exports.NOMEM = dns.NOMEM; -exports.DESTRUCTION = dns.DESTRUCTION; - -exports.NOTIMP = dns.NOTIMP; -exports.EREFUSED = dns.EREFUSED; -exports.SERVFAIL = dns.SERVFAIL; diff --git a/lib/net.js b/lib/net.js index 7d769e920a7..9968b667238 100644 --- a/lib/net.js +++ b/lib/net.js @@ -1,7 +1,7 @@ var sys = require("sys"); var fs = require("fs"); var events = require("events"); -var dns = require('dns_cares'); +var dns = require('dns'); var kMinPoolSpace = 128; var kPoolSize = 40*1024; diff --git a/src/node.cc b/src/node.cc index 412a666785d..131b8ca667d 100644 --- a/src/node.cc +++ b/src/node.cc @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -1186,15 +1185,6 @@ static Handle Binding(const Arguments& args) { binding_cache->Set(module, exports); } - } else if (!strcmp(*module_v, "dns")) { - if (binding_cache->Has(module)) { - exports = binding_cache->Get(module)->ToObject(); - } else { - exports = Object::New(); - DNS::Initialize(exports); - binding_cache->Set(module, exports); - } - } else if (!strcmp(*module_v, "cares")) { if (binding_cache->Has(module)) { exports = binding_cache->Get(module)->ToObject(); @@ -1276,7 +1266,6 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("buffer"), String::New(native_buffer)); exports->Set(String::New("child_process"),String::New(native_child_process)); exports->Set(String::New("dns"), String::New(native_dns)); - exports->Set(String::New("dns_cares"), String::New(native_dns_cares)); exports->Set(String::New("events"), String::New(native_events)); exports->Set(String::New("file"), String::New(native_file)); exports->Set(String::New("fs"), String::New(native_fs)); diff --git a/src/node_dns.cc b/src/node_dns.cc deleted file mode 100644 index e41c2e38adc..00000000000 --- a/src/node_dns.cc +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright 2009 Ryan Dahl -#include -#include - -#include /* exit() */ -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace node { - -using namespace v8; - -static ev_io io_watcher; -static ev_timer timer_watcher; - -static Persistent errno_symbol; -static Persistent exchange_symbol; -static Persistent priority_symbol; -static Persistent weight_symbol; -static Persistent port_symbol; -static Persistent name_symbol; - -static inline void set_timeout() { - int maxwait = 20; - int wait = dns_timeouts(NULL, maxwait, ev_now(EV_DEFAULT_UC)); - - ev_timer_stop(EV_DEFAULT_UC_ &timer_watcher); - - if (!dns_active(NULL)) return; - - if (wait >= 0) { - ev_timer_set(&timer_watcher, static_cast(wait), 0.0); - ev_timer_start(EV_DEFAULT_UC_ &timer_watcher); - } -} - -static inline void maybe_start() { - ev_io_start(EV_DEFAULT_UC_ &io_watcher); - set_timeout(); -} - -static void ioevent(EV_P_ ev_io *_watcher, int revents) { - assert(revents == EV_READ); - assert(_watcher == &io_watcher); - dns_ioevent(NULL, ev_now(EV_DEFAULT_UC)); - if (!dns_active(NULL)) ev_io_stop(EV_DEFAULT_UC_ &io_watcher); - set_timeout(); -} - -static void timeout(EV_P_ ev_timer *_watcher, int revents) { - assert(revents == EV_TIMEOUT); - assert(_watcher == &timer_watcher); - set_timeout(); -} - -static void ResolveError(Handle *cb) { - HandleScope scope; - int status = dns_status(NULL); - assert(status < 0); - - Local e = Exception::Error(String::NewSymbol(dns_strerror(status))); - Local obj = e->ToObject(); - obj->Set(errno_symbol, Integer::New(status)); - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 1, &e); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } -} - -static void AfterResolveA4(struct dns_ctx *ctx, - struct dns_rr_a4 *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnsa4_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnsa4_ttl); - - Local addresses = Array::New(result->dnsa4_nrr); - for (int i = 0; i < result->dnsa4_nrr; i++) { - HandleScope loop_scope; - - char ip[INET_ADDRSTRLEN]; - dns_ntop(AF_INET, &(result->dnsa4_addr[i]), ip, INET_ADDRSTRLEN); - Local address = String::New(ip); - - addresses->Set(Integer::New(i), address); - } - - Local argv[4] = { Local::New(Null()), addresses, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static void AfterResolveA6(struct dns_ctx *ctx, - struct dns_rr_a6 *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnsa6_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnsa6_ttl); - - Local addresses = Array::New(result->dnsa6_nrr); - for (int i = 0; i < result->dnsa6_nrr; i++) { - HandleScope loop_scope; - - char ip[INET6_ADDRSTRLEN]; - dns_ntop(AF_INET6, &(result->dnsa6_addr[i]), ip, INET6_ADDRSTRLEN); - Local address = String::New(ip); - - addresses->Set(Integer::New(i), address); - } - - Local argv[4] = { Local::New(Null()), addresses, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static void AfterResolveMX(struct dns_ctx *ctx, - struct dns_rr_mx *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnsmx_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnsmx_ttl); - - Local exchanges = Array::New(result->dnsmx_nrr); - for (int i = 0; i < result->dnsmx_nrr; i++) { - HandleScope loop_scope; - - Local exchange = Object::New(); - - struct dns_mx *mx = &(result->dnsmx_mx[i]); - exchange->Set(exchange_symbol, String::New(mx->name)); - exchange->Set(priority_symbol, Integer::New(mx->priority)); - - exchanges->Set(Integer::New(i), exchange); - } - - Local argv[4] = { Local::New(Null()), exchanges, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static void AfterResolveTXT(struct dns_ctx *ctx, - struct dns_rr_txt *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnstxt_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnstxt_ttl); - - Local records = Array::New(result->dnstxt_nrr); - for (int i = 0; i < result->dnstxt_nrr; i++) { - HandleScope loop_scope; - - struct dns_txt *record = &(result->dnstxt_txt[i]); - const char *txt = (const char *)record->txt; - records->Set(Integer::New(i), String::New(txt)); - } - - Local argv[4] = { Local::New(Null()), records, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static void AfterResolveSRV(struct dns_ctx *ctx, - struct dns_rr_srv *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnssrv_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnssrv_ttl); - - Local records = Array::New(result->dnssrv_nrr); - for (int i = 0; i < result->dnssrv_nrr; i++) { - HandleScope loop_scope; - - Local record = Object::New(); - - struct dns_srv *srv = &(result->dnssrv_srv[i]); - record->Set(priority_symbol, Integer::New(srv->priority)); - record->Set(weight_symbol, Integer::New(srv->weight)); - record->Set(port_symbol, Integer::New(srv->port)); - record->Set(name_symbol, String::New(srv->name)); - - records->Set(Integer::New(i), record); - } - - Local argv[4] = { Local::New(Null()), records, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static Handle ResolveA(int type, const Arguments& args) { - HandleScope scope; - - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error( - String::New("Argument must be a string."))); - } - - if (!args[1]->IsFunction()) { - return ThrowException(Exception::Error( - String::New("Missing callback argument"))); - } - - String::Utf8Value name(args[0]->ToString()); - - struct dns_query *query; - switch (type) { - case DNS_T_A: - query = dns_submit_a4(NULL, *name, 0, AfterResolveA4, cb_persist(args[1])); - break; - - case DNS_T_AAAA: - query = dns_submit_a6(NULL, *name, 0, AfterResolveA6, cb_persist(args[1])); - break; - - case DNS_T_MX: - query = dns_submit_mx(NULL, *name, 0, AfterResolveMX, cb_persist(args[1])); - break; - - case DNS_T_TXT: - query = dns_submit_txt(NULL, *name, DNS_C_IN, 0, AfterResolveTXT, cb_persist(args[1])); - break; - - case DNS_T_SRV: - query = dns_submit_srv(NULL, *name, NULL, NULL, 0, AfterResolveSRV, cb_persist(args[1])); - break; - - default: - return ThrowException(Exception::Error(String::New("Unsupported type"))); - } - - assert(query); // TODO(ry) better error handling. - - maybe_start(); - - return Undefined(); -} - -static Handle ResolveA4(const Arguments& args) { - return ResolveA(DNS_T_A, args); -} - -static Handle ResolveA6(const Arguments& args) { - return ResolveA(DNS_T_AAAA, args); -} - -static Handle ResolveMX(const Arguments& args) { - return ResolveA(DNS_T_MX, args); -} - -static Handle ResolveTXT(const Arguments& args) { - return ResolveA(DNS_T_TXT, args); -} - -static Handle ResolveSRV(const Arguments& args) { - return ResolveA(DNS_T_SRV, args); -} - -static void AfterReverse(struct dns_ctx *ctx, - struct dns_rr_ptr *result, - void *data) { - assert(ctx == &dns_defctx); - - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (result == NULL) { - ResolveError(cb); - cb_destroy(cb); - return; - } - - /* canonical name */ - Local cname = String::New(result->dnsptr_cname); - - /* Time-To-Live (TTL) value */ - Local ttl = Integer::New(result->dnsptr_ttl); - - Local domains = Array::New(); - - for (int i = 0; i < result->dnsptr_nrr; i++) { - HandleScope loop_scope; - - Local domain = String::New(result->dnsptr_ptr[i]); - domains->Set(Integer::New(i), domain); - } - - Local argv[4] = { Local::New(Null()), domains, ttl, cname }; - - TryCatch try_catch; - - (*cb)->Call(Context::GetCurrent()->Global(), 4, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - -static Handle Reverse(const Arguments& args) { - HandleScope scope; - - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error( - String::New("Argument must be a string."))); - } - - if (!args[1]->IsFunction()) { - return ThrowException(Exception::Error( - String::New("Missing callback argument"))); - } - - String::Utf8Value ip_address(args[0]->ToString()); - - union { - struct in_addr addr; - struct in6_addr addr6; - } a; - - bool v4; - - if (dns_pton(AF_INET, *ip_address, &a.addr) > 0) { - v4 = true; - } else if (dns_pton(AF_INET6, *ip_address, &a.addr6) > 0) { - v4 = false; - } else { - return ThrowException(Exception::Error(String::New("Invalid IP address"))); - } - - - struct dns_query *query; - - if (v4) { - query = dns_submit_a4ptr(NULL, &a.addr, AfterReverse, cb_persist(args[1])); - } else { - query = dns_submit_a6ptr(NULL, &a.addr6, AfterReverse, cb_persist(args[1])); - } - - assert(query); // TODO(ry) better error handling. - - maybe_start(); - - return Undefined(); -} - -void DNS::Initialize(Handle target) { - if (dns_init(NULL, 0) < 0) { - fprintf(stderr, "Error initializing UDNS context\n"); - exit(-2); - } - - int fd = dns_open(NULL); - - ev_io_init(&io_watcher, ioevent, fd, EV_READ); - ev_init(&timer_watcher, timeout); - - HandleScope scope; - - errno_symbol = NODE_PSYMBOL("errno"); - - exchange_symbol = NODE_PSYMBOL("exchange"); - priority_symbol = NODE_PSYMBOL("priority"); - weight_symbol = NODE_PSYMBOL("weight"); - port_symbol = NODE_PSYMBOL("port"); - name_symbol = NODE_PSYMBOL("name"); - - target->Set(String::NewSymbol("TEMPFAIL"), Integer::New(DNS_E_TEMPFAIL)); - target->Set(String::NewSymbol("PROTOCOL"), Integer::New(DNS_E_PROTOCOL)); - target->Set(String::NewSymbol("NXDOMAIN"), Integer::New(DNS_E_NXDOMAIN)); - target->Set(String::NewSymbol("NODATA"), Integer::New(DNS_E_NODATA)); - target->Set(String::NewSymbol("NOMEM"), Integer::New(DNS_E_NOMEM)); - target->Set(String::NewSymbol("BADQUERY"), Integer::New(DNS_E_BADQUERY)); - - Local resolve4 = FunctionTemplate::New(ResolveA4); - target->Set(String::NewSymbol("resolve4"), resolve4->GetFunction()); - - Local resolve6 = FunctionTemplate::New(ResolveA6); - target->Set(String::NewSymbol("resolve6"), resolve6->GetFunction()); - - Local resolveMx = FunctionTemplate::New(ResolveMX); - target->Set(String::NewSymbol("resolveMx"), resolveMx->GetFunction()); - - Local resolveTxt = FunctionTemplate::New(ResolveTXT); - target->Set(String::NewSymbol("resolveTxt"), resolveTxt->GetFunction()); - - Local resolveSrv = FunctionTemplate::New(ResolveSRV); - target->Set(String::NewSymbol("resolveSrv"), resolveSrv->GetFunction()); - - Local reverse = FunctionTemplate::New(Reverse); - target->Set(String::NewSymbol("reverse"), reverse->GetFunction()); -} - -} // namespace node diff --git a/src/node_dns.h b/src/node_dns.h deleted file mode 100644 index d0da0c9a87b..00000000000 --- a/src/node_dns.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2009 Ryan Dahl -#ifndef SRC_DNS_H_ -#define SRC_DNS_H_ - -#include -#include - -namespace node { - -class DNS { - public: - static void Initialize(v8::Handle target); -}; - -} // namespace node -#endif // SRC_DNS_H_ diff --git a/test/disabled/test-dns.js b/test/disabled/test-dns.js index 7121fffd45e..e2a0ac2a3bb 100644 --- a/test/disabled/test-dns.js +++ b/test/disabled/test-dns.js @@ -1,6 +1,6 @@ require("../common"); -var dns = require("dns_cares"), +var dns = require("dns"), child_process = require("child_process"), sys = require("sys"); diff --git a/test/simple/test-c-ares.js b/test/simple/test-c-ares.js index e24225e90e7..e84c240de68 100644 --- a/test/simple/test-c-ares.js +++ b/test/simple/test-c-ares.js @@ -1,6 +1,6 @@ require('../common'); -var dns = require("dns_cares"); +var dns = require("dns"); // Try resolution without callback diff --git a/wscript b/wscript index 1b5f10722eb..fb8f77907d1 100644 --- a/wscript +++ b/wscript @@ -157,10 +157,6 @@ def configure(conf): if not Options.options.system: conf.sub_config('deps/libev') conf.sub_config('deps/c-ares') - if sys.platform.startswith("sunos"): - conf_subproject(conf, 'deps/udns', 'LIBS="-lsocket -lnsl" ./configure') - else: - conf_subproject(conf, 'deps/udns', './configure') else: if not conf.check(lib='v8', uselib_store='V8'): conf.fatal("Cannot find V8") @@ -168,8 +164,6 @@ def configure(conf): conf.fatal("Cannot find libev") if not conf.check(lib='cares', uselib_store='CARES'): conf.fatal("Cannot find c-ares") - if not conf.check(lib='udns', uselib_store='UDNS'): - conf.fatal("Cannot find udns") conf.define("HAVE_CONFIG_H", 1) @@ -213,36 +207,6 @@ def configure(conf): conf.env.append_value('CXXFLAGS', ['-DNDEBUG', '-O3']) conf.write_config_header("config.h") -def build_udns(bld): - default_build_dir = bld.srcnode.abspath(bld.env_of_name("default")) - - default_dir = join(default_build_dir, "deps/udns") - - static_lib = bld.env["staticlib_PATTERN"] % "udns" - - rule = 'cd "%s" && make' - - default = bld.new_task_gen( - target= join("deps/udns", static_lib), - rule= rule % default_dir, - before= "cxx", - install_path= None - ) - - bld.env["CPPPATH_UDNS"] = "deps/udns" - t = join(bld.srcnode.abspath(bld.env_of_name("default")), default.target) - bld.env_of_name('default')["LINKFLAGS_UDNS"] = [t] - - if bld.env["USE_DEBUG"]: - debug_build_dir = bld.srcnode.abspath(bld.env_of_name("debug")) - debug_dir = join(debug_build_dir, "deps/udns") - debug = default.clone("debug") - debug.rule = rule % debug_dir - t = join(bld.srcnode.abspath(bld.env_of_name("debug")), debug.target) - bld.env_of_name('debug')["LINKFLAGS_UDNS"] = [t] - - bld.install_files('${PREFIX}/include/node/', 'deps/udns/udns.h') - def v8_cmd(bld, variant): scons = join(cwd, 'tools/scons/scons.py') @@ -308,7 +272,6 @@ def build(bld): if not bld.env["USE_SYSTEM"]: bld.add_subdirs('deps/libeio deps/libev deps/c-ares') - build_udns(bld) build_v8(bld) else: bld.add_subdirs('deps/libeio') @@ -413,7 +376,6 @@ def build(bld): src/node_io_watcher.cc src/node_child_process.cc src/node_constants.cc - src/node_dns.cc src/node_cares.cc src/node_events.cc src/node_file.cc @@ -431,7 +393,6 @@ def build(bld): deps/v8/include deps/libev deps/c-ares - deps/udns deps/libeio deps/evcom deps/http_parser @@ -443,7 +404,7 @@ def build(bld): node.add_objects = 'cares ev eio evcom http_parser coupling' node.uselib_local = '' - node.uselib = 'RT GNUTLS GPGERROR UDNS CARES V8 EXECINFO DL KVM SOCKET NSL' + node.uselib = 'RT GNUTLS GPGERROR CARES V8 EXECINFO DL KVM SOCKET NSL' else: node.includes = """ src/ @@ -454,7 +415,7 @@ def build(bld): """ node.add_objects = 'eio evcom http_parser coupling' node.uselib_local = 'eio' - node.uselib = 'RT EV GNUTLS GPGERROR UDNS CARES V8 EXECINFO DL KVM SOCKET NSL' + node.uselib = 'RT EV GNUTLS GPGERROR CARES V8 EXECINFO DL KVM SOCKET NSL' node.install_path = '${PREFIX}/lib' node.install_path = '${PREFIX}/bin' From cb84cde4d42637fd79ceacea1f0123995c23eea5 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 00:59:57 -0700 Subject: [PATCH 36/73] Enable TCP timeout by default --- lib/net.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/net.js b/lib/net.js index 9968b667238..029a88a5837 100644 --- a/lib/net.js +++ b/lib/net.js @@ -5,6 +5,7 @@ var dns = require('dns'); var kMinPoolSpace = 128; var kPoolSize = 40*1024; +var kDefaultTimeout = 60*1000; var debugLevel = process.env['NODE_DEBUG'] ? 1 : 0; function debug () { @@ -257,6 +258,8 @@ function _doFlush () { } function initStream (self) { + timeout.enroll(self, kDefaultTimeout); + self._readWatcher = ioWatchers.alloc(); self._readWatcher.callback = function () { // If this is the first recv (pool doesn't exist) or we've used up From 62277ab79b5cbdaba45693b33bfd55d61caa2f4a Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 01:00:29 -0700 Subject: [PATCH 37/73] Support both old and new HTTP closing APIs in benchmark program --- benchmark/http_simple.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 9bfeadb2cc5..4d9369c52a1 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -1,7 +1,7 @@ path = require("path"); var puts = require("sys").puts; -var old = false; +var old = true; http = require(old ? "http_old" : 'http'); if (old) puts('old version'); @@ -52,6 +52,10 @@ http.createServer(function (req, res) { , "Content-Length": content_length } ); - if (old) res.write(body, 'ascii'); - res.close(body, 'ascii'); + if (old) { + res.write(body, 'ascii'); + res.close(); + } else { + res.close(body, 'ascii'); + } }).listen(8000); From 7a6b5635eb565f3c4d858e76d0f8eae8d86e746c Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 07:19:42 -0700 Subject: [PATCH 38/73] Revert "Enable TCP timeout by default" Causing programs to not exit gracefully. This reverts commit cb84cde4d42637fd79ceacea1f0123995c23eea5. --- lib/net.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/net.js b/lib/net.js index 029a88a5837..9968b667238 100644 --- a/lib/net.js +++ b/lib/net.js @@ -5,7 +5,6 @@ var dns = require('dns'); var kMinPoolSpace = 128; var kPoolSize = 40*1024; -var kDefaultTimeout = 60*1000; var debugLevel = process.env['NODE_DEBUG'] ? 1 : 0; function debug () { @@ -258,8 +257,6 @@ function _doFlush () { } function initStream (self) { - timeout.enroll(self, kDefaultTimeout); - self._readWatcher = ioWatchers.alloc(); self._readWatcher.callback = function () { // If this is the first recv (pool doesn't exist) or we've used up From de9778b5bdc53d8011c4d3ac4ad8971635868223 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 8 Apr 2010 08:07:15 -0700 Subject: [PATCH 39/73] Add line breaks to the code when the user types a line break --- lib/repl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/repl.js b/lib/repl.js index 1608102b1f2..28bf15817cf 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -41,7 +41,7 @@ function readline (cmd) { // The catchall for errors try { - buffered_cmd += cmd; + buffered_cmd += "\n" + cmd; // This try is for determining if the command is complete, or should // continue onto the next line. try { From c16508c87ad86fd55fc5317efd89c92f90341603 Mon Sep 17 00:00:00 2001 From: Herbert Vojcik Date: Thu, 8 Apr 2010 16:15:56 +0200 Subject: [PATCH 40/73] Better require.async throw test --- test/fixtures/throws_error1.js | 1 + test/simple/test-module-loading.js | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 test/fixtures/throws_error1.js diff --git a/test/fixtures/throws_error1.js b/test/fixtures/throws_error1.js new file mode 100644 index 00000000000..728ece555f5 --- /dev/null +++ b/test/fixtures/throws_error1.js @@ -0,0 +1 @@ +throw new Error("blah"); diff --git a/test/simple/test-module-loading.js b/test/simple/test-module-loading.js index 56515b8850c..460c7942677 100644 --- a/test/simple/test-module-loading.js +++ b/test/simple/test-module-loading.js @@ -56,6 +56,14 @@ try { assert.equal("blah", e.message); } +var errorThrownAsync = false; +require.async("../fixtures/throws_error1", function(err, a) { + if (err) { + errorThrownAsync = true; + assert.equal("blah", err.message); + } +}); + assert.equal(require('path').dirname(__filename), __dirname); var asyncRun = false; @@ -103,5 +111,7 @@ process.addListener("exit", function () { assert.equal(true, asyncRun); + assert.equal(true, errorThrownAsync); + puts("exit"); }); From 3819920d77c065215bc4e226ca528fb4a8230ab0 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 10:22:55 -0700 Subject: [PATCH 41/73] Rename binding reference in fs.js --- lib/fs.js | 231 +++++++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 115 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 22dba6dc601..b75b69ababe 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1,9 +1,10 @@ var sys = require('sys'), events = require('events'); -var fs = process.binding('fs'); +var binding = process.binding('fs'); +var fs = exports; -exports.Stats = fs.Stats; +fs.Stats = binding.Stats; fs.Stats.prototype._checkModeProperty = function (property) { return ((this.mode & property) === property); @@ -39,7 +40,7 @@ fs.Stats.prototype.isSocket = function () { function readAll (fd, pos, content, encoding, callback) { - fs.read(fd, 4*1024, pos, encoding, function (err, chunk, bytesRead) { + binding.read(fd, 4*1024, pos, encoding, function (err, chunk, bytesRead) { if (err) { if (callback) callback(err); } else if (chunk) { @@ -47,18 +48,18 @@ function readAll (fd, pos, content, encoding, callback) { pos += bytesRead; readAll(fd, pos, content, encoding, callback); } else { - fs.close(fd, function (err) { + binding.close(fd, function (err) { if (callback) callback(err, content); }); } }); } -exports.readFile = function (path, encoding_, callback) { +fs.readFile = function (path, encoding_, callback) { var encoding = typeof(encoding_) == 'string' ? encoding_ : 'utf8'; var callback_ = arguments[arguments.length - 1]; var callback = (typeof(callback_) == 'function' ? callback_ : null); - fs.open(path, process.O_RDONLY, 0666, function (err, fd) { + binding.open(path, process.O_RDONLY, 0666, function (err, fd) { if (err) { if (callback) callback(err); } else { @@ -67,26 +68,26 @@ exports.readFile = function (path, encoding_, callback) { }); }; -exports.readFileSync = function (path, encoding) { +fs.readFileSync = function (path, encoding) { encoding = encoding || "utf8"; // default to utf8 - var fd = fs.open(path, process.O_RDONLY, 0666); + var fd = binding.open(path, process.O_RDONLY, 0666); var content = ''; var pos = 0; var r; - while ((r = fs.read(fd, 4*1024, pos, encoding)) && r[0]) { + while ((r = binding.read(fd, 4*1024, pos, encoding)) && r[0]) { content += r[0]; pos += r[1] } - fs.close(fd); + binding.close(fd); return content; }; -// Used by fs.open and friends +// Used by binding.open and friends function stringToFlags(flag) { // Only mess with strings if (typeof flag !== 'string') { @@ -108,157 +109,157 @@ function noop () {} // Yes, the follow could be easily DRYed up but I provide the explicit // list to make the arguments clear. -exports.close = function (fd, callback) { - fs.close(fd, callback || noop); +fs.close = function (fd, callback) { + binding.close(fd, callback || noop); }; -exports.closeSync = function (fd) { - return fs.close(fd); +fs.closeSync = function (fd) { + return binding.close(fd); }; -exports.open = function (path, flags, mode, callback) { +fs.open = function (path, flags, mode, callback) { if (mode === undefined) { mode = 0666; } - fs.open(path, stringToFlags(flags), mode, callback || noop); + binding.open(path, stringToFlags(flags), mode, callback || noop); }; -exports.openSync = function (path, flags, mode) { +fs.openSync = function (path, flags, mode) { if (mode === undefined) { mode = 0666; } - return fs.open(path, stringToFlags(flags), mode); + return binding.open(path, stringToFlags(flags), mode); }; -exports.read = function (fd, length, position, encoding, callback) { +fs.read = function (fd, length, position, encoding, callback) { encoding = encoding || "binary"; - fs.read(fd, length, position, encoding, callback || noop); + binding.read(fd, length, position, encoding, callback || noop); }; -exports.readSync = function (fd, length, position, encoding) { +fs.readSync = function (fd, length, position, encoding) { encoding = encoding || "binary"; - return fs.read(fd, length, position, encoding); + return binding.read(fd, length, position, encoding); }; -exports.write = function (fd, data, position, encoding, callback) { +fs.write = function (fd, data, position, encoding, callback) { encoding = encoding || "binary"; - fs.write(fd, data, position, encoding, callback || noop); + binding.write(fd, data, position, encoding, callback || noop); }; -exports.writeSync = function (fd, data, position, encoding) { +fs.writeSync = function (fd, data, position, encoding) { encoding = encoding || "binary"; - return fs.write(fd, data, position, encoding); + return binding.write(fd, data, position, encoding); }; -exports.rename = function (oldPath, newPath, callback) { - fs.rename(oldPath, newPath, callback || noop); +fs.rename = function (oldPath, newPath, callback) { + binding.rename(oldPath, newPath, callback || noop); }; -exports.renameSync = function (oldPath, newPath) { - return fs.rename(oldPath, newPath); +fs.renameSync = function (oldPath, newPath) { + return binding.rename(oldPath, newPath); }; -exports.truncate = function (fd, len, callback) { - fs.truncate(fd, len, callback || noop); +fs.truncate = function (fd, len, callback) { + binding.truncate(fd, len, callback || noop); }; -exports.truncateSync = function (fd, len) { - return fs.truncate(fd, len); +fs.truncateSync = function (fd, len) { + return binding.truncate(fd, len); }; -exports.rmdir = function (path, callback) { - fs.rmdir(path, callback || noop); +fs.rmdir = function (path, callback) { + binding.rmdir(path, callback || noop); }; -exports.rmdirSync = function (path) { - return fs.rmdir(path); +fs.rmdirSync = function (path) { + return binding.rmdir(path); }; -exports.mkdir = function (path, mode, callback) { - fs.mkdir(path, mode, callback || noop); +fs.mkdir = function (path, mode, callback) { + binding.mkdir(path, mode, callback || noop); }; -exports.mkdirSync = function (path, mode) { - return fs.mkdir(path, mode); +fs.mkdirSync = function (path, mode) { + return binding.mkdir(path, mode); }; -exports.sendfile = function (outFd, inFd, inOffset, length, callback) { - fs.sendfile(outFd, inFd, inOffset, length, callback || noop); +fs.sendfile = function (outFd, inFd, inOffset, length, callback) { + binding.sendfile(outFd, inFd, inOffset, length, callback || noop); }; -exports.sendfileSync = function (outFd, inFd, inOffset, length) { - return fs.sendfile(outFd, inFd, inOffset, length); +fs.sendfileSync = function (outFd, inFd, inOffset, length) { + return binding.sendfile(outFd, inFd, inOffset, length); }; -exports.readdir = function (path, callback) { - fs.readdir(path, callback || noop); +fs.readdir = function (path, callback) { + binding.readdir(path, callback || noop); }; -exports.readdirSync = function (path) { - return fs.readdir(path); +fs.readdirSync = function (path) { + return binding.readdir(path); }; -exports.lstat = function (path, callback) { - fs.lstat(path, callback || noop); +fs.lstat = function (path, callback) { + binding.lstat(path, callback || noop); }; -exports.stat = function (path, callback) { - fs.stat(path, callback || noop); +fs.stat = function (path, callback) { + binding.stat(path, callback || noop); }; -exports.lstatSync = function (path) { - return fs.lstat(path); +fs.lstatSync = function (path) { + return binding.lstat(path); }; -exports.statSync = function (path) { - return fs.stat(path); +fs.statSync = function (path) { + return binding.stat(path); }; -exports.readlink = function (path, callback) { - fs.readlink(path, callback || noop); +fs.readlink = function (path, callback) { + binding.readlink(path, callback || noop); }; -exports.readlinkSync = function (path) { - return fs.readlink(path); +fs.readlinkSync = function (path) { + return binding.readlink(path); }; -exports.symlink = function (destination, path, callback) { - fs.symlink(destination, path, callback || noop); +fs.symlink = function (destination, path, callback) { + binding.symlink(destination, path, callback || noop); }; -exports.symlinkSync = function (destination, path) { - return fs.symlink(destination, path); +fs.symlinkSync = function (destination, path) { + return binding.symlink(destination, path); }; -exports.link = function (srcpath, dstpath, callback) { - fs.link(srcpath, dstpath, callback || noop); +fs.link = function (srcpath, dstpath, callback) { + binding.link(srcpath, dstpath, callback || noop); }; -exports.linkSync = function (srcpath, dstpath) { - return fs.link(srcpath, dstpath); +fs.linkSync = function (srcpath, dstpath) { + return binding.link(srcpath, dstpath); }; -exports.unlink = function (path, callback) { - fs.unlink(path, callback || noop); +fs.unlink = function (path, callback) { + binding.unlink(path, callback || noop); }; -exports.unlinkSync = function (path) { - return fs.unlink(path); +fs.unlinkSync = function (path) { + return binding.unlink(path); }; -exports.chmod = function (path, mode, callback) { - fs.chmod(path, mode, callback || noop); +fs.chmod = function (path, mode, callback) { + binding.chmod(path, mode, callback || noop); }; -exports.chmodSync = function (path, mode) { - return fs.chmod(path, mode); +fs.chmodSync = function (path, mode) { + return binding.chmod(path, mode); }; function writeAll (fd, data, encoding, callback) { - exports.write(fd, data, 0, encoding, function (writeErr, written) { + fs.write(fd, data, 0, encoding, function (writeErr, written) { if (writeErr) { - exports.close(fd, function () { + fs.close(fd, function () { if (callback) callback(writeErr); }); } else { if (written === data.length) { - exports.close(fd, callback); + fs.close(fd, callback); } else { writeAll(fd, data.slice(written), encoding, callback); } @@ -266,11 +267,11 @@ function writeAll (fd, data, encoding, callback) { }); } -exports.writeFile = function (path, data, encoding_, callback) { +fs.writeFile = function (path, data, encoding_, callback) { var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); var callback_ = arguments[arguments.length - 1]; var callback = (typeof(callback_) == 'function' ? callback_ : null); - exports.open(path, 'w', 0666, function (openErr, fd) { + fs.open(path, 'w', 0666, function (openErr, fd) { if (openErr) { if (callback) callback(openErr); } else { @@ -279,23 +280,23 @@ exports.writeFile = function (path, data, encoding_, callback) { }); }; -exports.writeFileSync = function (path, data, encoding) { +fs.writeFileSync = function (path, data, encoding) { encoding = encoding || "utf8"; // default to utf8 - var fd = exports.openSync(path, "w"); + var fd = fs.openSync(path, "w"); var written = 0; while (written < data.length) { - written += exports.writeSync(fd, data, 0, encoding); + written += fs.writeSync(fd, data, 0, encoding); data = data.slice(written); } - exports.closeSync(fd); + fs.closeSync(fd); }; -exports.cat = function () { +fs.cat = function () { throw new Error("fs.cat is deprecated. Please use fs.readFile instead."); }; -exports.catSync = function () { +fs.catSync = function () { throw new Error("fs.catSync is deprecated. Please use fs.readFileSync instead."); }; @@ -303,7 +304,7 @@ exports.catSync = function () { var statWatchers = {}; -exports.watchFile = function (filename) { +fs.watchFile = function (filename) { var stat; var options; var listener; @@ -322,7 +323,7 @@ exports.watchFile = function (filename) { if (statWatchers[filename]) { stat = statWatchers[filename]; } else { - statWatchers[filename] = new fs.StatWatcher(); + statWatchers[filename] = new binding.StatWatcher(); stat = statWatchers[filename]; stat.start(filename, options.persistent, options.interval); } @@ -330,7 +331,7 @@ exports.watchFile = function (filename) { return stat; }; -exports.unwatchFile = function (filename) { +fs.unwatchFile = function (filename) { if (statWatchers[filename]) { stat = statWatchers[filename]; stat.stop(); @@ -344,7 +345,7 @@ var path = require('path'); var normalize = path.normalize normalizeArray = path.normalizeArray; -exports.realpathSync = function (path) { +fs.realpathSync = function (path) { var seen_links = {}, knownHards = {}, buf, i = 0, part, x, stats; if (path.charAt(0) !== '/') { var cwd = process.cwd().split('/'); @@ -362,13 +363,13 @@ exports.realpathSync = function (path) { if (part in knownHards) { buf.push(path[i]); } else { - stats = exports.lstatSync(part); + stats = fs.lstatSync(part); if (stats.isSymbolicLink()) { x = stats.dev.toString(32)+":"+stats.ino.toString(32); if (x in seen_links) throw new Error("cyclic link at "+part); seen_links[x] = true; - part = exports.readlinkSync(part); + part = fs.readlinkSync(part); if (part.charAt(0) === '/') { // absolute path = normalizeArray(part.split('/')); @@ -400,7 +401,7 @@ exports.realpathSync = function (path) { } -exports.realpath = function (path, callback) { +fs.realpath = function (path, callback) { var seen_links = {}, knownHards = {}, buf = [''], i = 0, part, x; if (path.charAt(0) !== '/') { // assumes cwd is canonical @@ -426,14 +427,14 @@ exports.realpath = function (path, callback) { buf.push(path[i]); next(); } else { - exports.lstat(part, function(err, stats){ + fs.lstat(part, function(err, stats){ if (err) return done(err); if (stats.isSymbolicLink()) { x = stats.dev.toString(32)+":"+stats.ino.toString(32); if (x in seen_links) return done(new Error("cyclic link at "+part)); seen_links[x] = true; - exports.readlink(part, function(err, npart){ + fs.readlink(part, function(err, npart){ if (err) return done(err); part = npart; if (part.charAt(0) === '/') { @@ -458,24 +459,24 @@ exports.realpath = function (path, callback) { } } next(); - }); // fs.readlink + }); // binding.readlink } else { buf.push(path[i]); knownHards[buf.join('/')] = true; next(); } - }); // fs.lstat + }); // binding.lstat } } next(); } -exports.createReadStream = function(path, options) { +fs.createReadStream = function(path, options) { return new FileReadStream(path, options); }; -var FileReadStream = exports.FileReadStream = function(path, options) { +var FileReadStream = fs.FileReadStream = function(path, options) { events.EventEmitter.call(this); this.path = path; @@ -500,7 +501,7 @@ var FileReadStream = exports.FileReadStream = function(path, options) { return; } - exports.read(self.fd, self.bufferSize, undefined, self.encoding, function(err, data, bytesRead) { + fs.read(self.fd, self.bufferSize, undefined, self.encoding, function(err, data, bytesRead) { if (err) { self.emit('error', err); self.readable = false; @@ -529,7 +530,7 @@ var FileReadStream = exports.FileReadStream = function(path, options) { }); } - exports.open(this.path, this.flags, this.mode, function(err, fd) { + fs.open(this.path, this.flags, this.mode, function(err, fd) { if (err) { self.emit('error', err); self.readable = false; @@ -545,7 +546,7 @@ var FileReadStream = exports.FileReadStream = function(path, options) { this.readable = false; function close() { - exports.close(self.fd, function(err) { + fs.close(self.fd, function(err) { if (err) { if (cb) { cb(err); @@ -585,11 +586,11 @@ var FileReadStream = exports.FileReadStream = function(path, options) { }; sys.inherits(FileReadStream, events.EventEmitter); -exports.createWriteStream = function(path, options) { +fs.createWriteStream = function(path, options) { return new FileWriteStream(path, options); }; -var FileWriteStream = exports.FileWriteStream = function(path, options) { +var FileWriteStream = fs.FileWriteStream = function(path, options) { events.EventEmitter.call(this); this.path = path; @@ -608,7 +609,7 @@ var FileWriteStream = exports.FileWriteStream = function(path, options) { queue = [], busy = false; - queue.push([exports.open, this.path, this.flags, this.mode, undefined]); + queue.push([fs.open, this.path, this.flags, this.mode, undefined]); function flush() { if (busy) { @@ -639,7 +640,7 @@ var FileWriteStream = exports.FileWriteStream = function(path, options) { } // stop flushing after close - if (method === exports.close) { + if (method === fs.close) { if (cb) { cb(null); } @@ -648,7 +649,7 @@ var FileWriteStream = exports.FileWriteStream = function(path, options) { } // save reference for file pointer - if (method === exports.open) { + if (method === fs.open) { self.fd = arguments[1]; self.emit('open', self.fd); } else if (cb) { @@ -660,7 +661,7 @@ var FileWriteStream = exports.FileWriteStream = function(path, options) { }); // Inject the file pointer - if (method !== exports.open) { + if (method !== fs.open) { args.unshift(self.fd); } @@ -672,20 +673,20 @@ var FileWriteStream = exports.FileWriteStream = function(path, options) { throw new Error('stream not writeable'); } - queue.push([exports.write, data, undefined, this.encoding, cb]); + queue.push([fs.write, data, undefined, this.encoding, cb]); flush(); return false; }; this.close = function(cb) { this.writeable = false; - queue.push([exports.close, cb]); + queue.push([fs.close, cb]); flush(); }; this.forceClose = function(cb) { this.writeable = false; - exports.close(self.fd, function(err) { + fs.close(self.fd, function(err) { if (err) { if (cb) { cb(err); From 7faf7d5c8d5ddb35548a0754f0c0fc3ad713c195 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 10:37:10 -0700 Subject: [PATCH 42/73] Put file stream methods into prototype, small style fixes --- lib/fs.js | 351 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 181 insertions(+), 170 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index b75b69ababe..25ce376d5a8 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -492,43 +492,7 @@ var FileReadStream = fs.FileReadStream = function(path, options) { options = options || {}; for (var i in options) this[i] = options[i]; - var - self = this, - buffer = null; - - function read() { - if (!self.readable || self.paused) { - return; - } - - fs.read(self.fd, self.bufferSize, undefined, self.encoding, function(err, data, bytesRead) { - if (err) { - self.emit('error', err); - self.readable = false; - return; - } - - if (bytesRead === 0) { - self.emit('end'); - self.forceClose(); - return; - } - - // do not emit events if the stream is paused - if (self.paused) { - buffer = data; - return; - } - - // do not emit events anymore after we declared the stream unreadable - if (!self.readable) { - return; - } - - self.emit('data', data); - read(); - }); - } + var self = this; fs.open(this.path, this.flags, this.mode, function(err, fd) { if (err) { @@ -539,53 +503,97 @@ var FileReadStream = fs.FileReadStream = function(path, options) { self.fd = fd; self.emit('open', fd); - read(); + self._read(); }); - - this.forceClose = function(cb) { - this.readable = false; - - function close() { - fs.close(self.fd, function(err) { - if (err) { - if (cb) { - cb(err); - } - self.emit('error', err); - return; - } - - if (cb) { - cb(null); - } - self.emit('close'); - }); - } - - if (this.fd) { - close(); - } else { - this.addListener('open', close); - } - }; - - this.pause = function() { - this.paused = true; - }; - - this.resume = function() { - this.paused = false; - - if (buffer !== null) { - self.emit('data', buffer); - buffer = null; - } - - read(); - }; }; sys.inherits(FileReadStream, events.EventEmitter); + +FileReadStream.prototype._read = function () { + var self = this; + if (!self.readable || self.paused) return; + + fs.read(self.fd, + self.bufferSize, + undefined, + self.encoding, + function(err, data, bytesRead) { + if (err) { + self.emit('error', err); + self.readable = false; + return; + } + + if (bytesRead === 0) { + self.emit('end'); + self.forceClose(); + return; + } + + // do not emit events if the stream is paused + if (self.paused) { + self.buffer = data; + return; + } + + // do not emit events anymore after we declared the stream unreadable + if (!self.readable) { + return; + } + + self.emit('data', data); + self._read(); + }); +}; + + +FileReadStream.prototype.forceClose = function (cb) { + var self = this; + this.readable = false; + + function close() { + fs.close(self.fd, function(err) { + if (err) { + if (cb) { + cb(err); + } + self.emit('error', err); + return; + } + + if (cb) { + cb(null); + } + self.emit('close'); + }); + } + + if (this.fd) { + close(); + } else { + this.addListener('open', close); + } +}; + + +FileReadStream.prototype.pause = function() { + this.paused = true; +}; + + +FileReadStream.prototype.resume = function() { + this.paused = false; + + if (this.buffer) { + this.emit('data', this.buffer); + this.buffer = null; + } + + this._read(); +}; + + + fs.createWriteStream = function(path, options) { return new FileWriteStream(path, options); }; @@ -604,105 +612,108 @@ var FileWriteStream = fs.FileWriteStream = function(path, options) { options = options || {}; for (var i in options) this[i] = options[i]; + this.busy = false; + this._queue = []; + + this._queue.push([fs.open, this.path, this.flags, this.mode, undefined]); + this.flush(); +}; +sys.inherits(FileWriteStream, events.EventEmitter); + + + +FileWriteStream.prototype.flush = function () { + if (this.busy) return; + var self = this; + + var args = this._queue.shift(); + if (!args) return self.emit('drain'); + + this.busy = true; + var - self = this, - queue = [], - busy = false; + method = args.shift(), + cb = args.pop(); - queue.push([fs.open, this.path, this.flags, this.mode, undefined]); + var self = this; - function flush() { - if (busy) { + args.push(function(err) { + self.busy = false; + + if (err) { + self.writeable = false; + if (cb) { + cb(err); + } + self.emit('error', err); return; } - var args = queue.shift(); - if (!args) { - return self.emit('drain'); - } - - busy = true; - - var - method = args.shift(), - cb = args.pop(); - - args.push(function(err) { - busy = false; - - if (err) { - self.writeable = false; - if (cb) { - cb(err); - } - self.emit('error', err); - return; - } - - // stop flushing after close - if (method === fs.close) { - if (cb) { - cb(null); - } - self.emit('close'); - return; - } - - // save reference for file pointer - if (method === fs.open) { - self.fd = arguments[1]; - self.emit('open', self.fd); - } else if (cb) { - // write callback - cb(null, arguments[1]); - } - - flush(); - }); - - // Inject the file pointer - if (method !== fs.open) { - args.unshift(self.fd); - } - - method.apply(this, args); - }; - - this.write = function(data, cb) { - if (!this.writeable) { - throw new Error('stream not writeable'); - } - - queue.push([fs.write, data, undefined, this.encoding, cb]); - flush(); - return false; - }; - - this.close = function(cb) { - this.writeable = false; - queue.push([fs.close, cb]); - flush(); - }; - - this.forceClose = function(cb) { - this.writeable = false; - fs.close(self.fd, function(err) { - if (err) { - if (cb) { - cb(err); - } - - self.emit('error', err); - return; - } - + // stop flushing after close + if (method === fs.close) { if (cb) { cb(null); } self.emit('close'); - }); - }; + return; + } - flush(); + // save reference for file pointer + if (method === fs.open) { + self.fd = arguments[1]; + self.emit('open', self.fd); + } else if (cb) { + // write callback + cb(null, arguments[1]); + } + + self.flush(); + }); + + // Inject the file pointer + if (method !== fs.open) { + args.unshift(self.fd); + } + + method.apply(this, args); }; -sys.inherits(FileWriteStream, events.EventEmitter); + + +FileWriteStream.prototype.write = function(data, cb) { + if (!this.writeable) { + throw new Error('stream not writeable'); + } + + this._queue.push([fs.write, data, undefined, this.encoding, cb]); + this.flush(); + + return false; +}; + + +FileWriteStream.prototype.close = function (cb) { + this.writeable = false; + this._queue.push([fs.close, cb]); + this.flush(); +}; + + +FileWriteStream.prototype.forceClose = function (cb) { + this.writeable = false; + fs.close(self.fd, function(err) { + if (err) { + if (cb) { + cb(err); + } + + self.emit('error', err); + return; + } + + if (cb) { + cb(null); + } + self.emit('close'); + }); +}; + From 50c70ac7149907f00cea01dfb39703590c54de42 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 10:44:22 -0700 Subject: [PATCH 43/73] Update stream API: forceClose() -> destroy(), close() -> end() --- benchmark/http_simple.js | 4 +- lib/fs.js | 35 ++++++++++++++- lib/http.js | 43 +++++++++++++++---- lib/net.js | 40 ++++++++++++----- test/pummel/test-http-client-reconnect-bug.js | 4 +- test/pummel/test-keep-alive.js | 2 +- test/pummel/test-tcp-many-clients.js | 4 +- test/pummel/test-tcp-pause.js | 4 +- test/pummel/test-tcp-pingpong-delay.js | 14 +++--- test/pummel/test-tcp-pingpong.js | 4 +- test/pummel/test-tcp-throttle.js | 4 +- test/pummel/test-tcp-timeout.js | 4 +- test/pummel/test-tcp-tls.js | 4 +- test/simple/test-child-process-ipc.js | 2 +- test/simple/test-child-process-stdin.js | 2 +- test/simple/test-file-read-stream.js | 6 +-- test/simple/test-file-write-stream.js | 6 +-- test/simple/test-http-1.0.js | 4 +- test/simple/test-http-cat.js | 2 +- test/simple/test-http-chunked.js | 2 +- test/simple/test-http-client-race.js | 6 +-- test/simple/test-http-client-upload.js | 4 +- test/simple/test-http-malformed-request.js | 4 +- test/simple/test-http-proxy.js | 8 ++-- test/simple/test-http-server.js | 4 +- test/simple/test-http-tls.js | 6 +-- test/simple/test-http-wget.js | 4 +- test/simple/test-http.js | 6 +-- test/simple/test-net-pingpong.js | 8 ++-- test/simple/test-remote-module-loading.js | 2 +- test/simple/test-tcp-binary.js | 4 +- test/simple/test-tcp-reconnect.js | 4 +- 32 files changed, 164 insertions(+), 86 deletions(-) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 4d9369c52a1..28c215aaf5e 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -1,7 +1,7 @@ path = require("path"); var puts = require("sys").puts; -var old = true; +var old = false; http = require(old ? "http_old" : 'http'); if (old) puts('old version'); @@ -56,6 +56,6 @@ http.createServer(function (req, res) { res.write(body, 'ascii'); res.close(); } else { - res.close(body, 'ascii'); + res.end(body, 'ascii'); } }).listen(8000); diff --git a/lib/fs.js b/lib/fs.js index 25ce376d5a8..2157bc1b444 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -526,7 +526,7 @@ FileReadStream.prototype._read = function () { if (bytesRead === 0) { self.emit('end'); - self.forceClose(); + self.destroy(); return; } @@ -547,7 +547,18 @@ FileReadStream.prototype._read = function () { }; +var readStreamForceCloseWarning; + FileReadStream.prototype.forceClose = function (cb) { + if (!readStreamForceCloseWarning) { + readStreamForceCloseWarning = "FileReadStream.prototype.forceClose renamed to destroy()"; + sys.error(readStreamForceCloseWarning); + } + return this.destroy(cb); +} + + +FileReadStream.prototype.destroy = function (cb) { var self = this; this.readable = false; @@ -691,13 +702,35 @@ FileWriteStream.prototype.write = function(data, cb) { }; +var writeStreamCloseWarning; + FileWriteStream.prototype.close = function (cb) { + if (!writeStreamCloseWarning) { + writeStreamCloseWarning = "FileWriteStream.prototype.close renamed to end()"; + sys.error(writeStreamCloseWarning); + } + return this.end(cb); +} + + +FileWriteStream.prototype.end = function (cb) { this.writeable = false; this._queue.push([fs.close, cb]); this.flush(); }; +var writeStreamForceCloseWarning; + +FileWriteStream.prototype.forceClose = function (cb) { + if (!writeStreamForceCloseWarning) { + writeStreamForceCloseWarning = "FileWriteStream.prototype.forceClose renamed to destroy()"; + sys.error(writeStreamForceCloseWarning); + } + return this.destroy(cb); +} + + FileWriteStream.prototype.forceClose = function (cb) { this.writeable = false; fs.close(self.fd, function(err) { diff --git a/lib/http.js b/lib/http.js index 353c7daa79f..d0ae3064c59 100644 --- a/lib/http.js +++ b/lib/http.js @@ -372,7 +372,17 @@ OutgoingMessage.prototype.finish = function () { throw new Error("finish() has been renamed to close()."); }; +var closeWarning; + OutgoingMessage.prototype.close = function (data, encoding) { + if (!closeWarning) { + closeWarning = "OutgoingMessage.prototype.close has been renamed to end()"; + sys.error(closeWarning); + } + return this.end(data, encoding); +}; + +OutgoingMessage.prototype.end = function (data, encoding) { if (data) this.write(data, encoding); if (this.chunkedEncoding) this._send("0\r\n\r\n"); // last chunk this.finished = true; @@ -436,19 +446,34 @@ sys.inherits(ClientRequest, OutgoingMessage); exports.ClientRequest = ClientRequest; ClientRequest.prototype.finish = function () { - throw new Error( "finish() has been renamed to close() and no longer takes " + throw new Error( "finish() has been renamed to end() and no longer takes " + "a response handler as an argument. Manually add a 'response' listener " + "to the request object." ); }; +var clientRequestCloseWarning; + ClientRequest.prototype.close = function () { + if (!clientRequestCloseWarning) { + clientRequestCloseWarning = "Warning: ClientRequest.prototype.close has been renamed to end()"; + sys.error(clientRequestCloseWarning); + } if (arguments.length > 0) { - throw new Error( "ClientRequest.prototype.close does not take any arguments. " + throw new Error( "ClientRequest.prototype.end does not take any arguments. " + "Add a response listener manually to the request object." ); } - OutgoingMessage.prototype.close.call(this); + return this.end(); +}; + +ClientRequest.prototype.end = function () { + if (arguments.length > 0) { + throw new Error( "ClientRequest.prototype.end does not take any arguments. " + + "Add a response listener manually to the request object." + ); + } + OutgoingMessage.prototype.end.call(this); }; @@ -509,7 +534,7 @@ function connectionListener (socket) { freeParser(parser); if (responses.length == 0) { - socket.close(); + socket.end(); } else { responses[responses.length-1].closeOnFinish = true; } @@ -525,7 +550,7 @@ function connectionListener (socket) { res.shouldKeepAlive = shouldKeepAlive; res.addListener('flush', function () { if (flushMessageQueue(socket, responses)) { - socket.close(); + socket.end(); } }); responses.push(res); @@ -582,7 +607,7 @@ function Client ( ) { parser.finish(); debug("self got end closing. readyState = " + self.readyState); - self.close(); + self.end(); }); self.addListener("close", function (e) { @@ -604,7 +629,7 @@ function Client ( ) { res.addListener('end', function ( ) { debug("request complete disconnecting. readyState = " + self.readyState); - self.close(); + self.end(); }); currentRequest.emit("response", res); @@ -697,7 +722,7 @@ exports.cat = function (url, encoding_, headers_) { req.addListener('response', function (res) { if (res.statusCode < 200 || res.statusCode >= 300) { if (callback) callback(res.statusCode); - client.close(); + client.end(); return; } res.setBodyEncoding(encoding); @@ -711,5 +736,5 @@ exports.cat = function (url, encoding_, headers_) { if (callback) callback(err); }); - req.close(); + req.end(); }; diff --git a/lib/net.js b/lib/net.js index 9968b667238..ff616eb9643 100644 --- a/lib/net.js +++ b/lib/net.js @@ -136,7 +136,7 @@ var timeout = new (function () { remove(first); assert(first != peek(list)); first.emit('timeout'); - first.forceClose(new Error('idle timeout')); + first.destroy(new Error('idle timeout')); } } debug(msecs + ' list empty'); @@ -277,7 +277,7 @@ function initStream (self) { pool.used, pool.length - pool.used); } catch (e) { - self.forceClose(e); + self.destroy(e); return; } @@ -290,7 +290,7 @@ function initStream (self) { if (self._events && self._events['end']) self.emit('end'); if (self.onend) self.onend(); - if (!self.writable) self.forceClose(); + if (!self.writable) self.destroy(); } else if (bytesRead > 0) { timeout.active(self); @@ -485,7 +485,7 @@ Stream.prototype._writeOut = function (data, encoding) { try { bytesWritten = write(this.fd, buffer, off, len); } catch (e) { - this.forceClose(e); + this.destroy(e); return false; } @@ -563,7 +563,7 @@ function doConnect (socket, port, host) { try { connect(socket.fd, port, host); } catch (e) { - socket.forceClose(e); + socket.destroy(e); return; } @@ -589,7 +589,7 @@ function doConnect (socket, port, host) { socket._writeWatcher.callback = _doFlush; socket.emit('connect'); } else if (errno != EINPROGRESS) { - socket.forceClose(errnoException(errno, 'connect')); + socket.destroy(errnoException(errno, 'connect')); } }; } @@ -660,7 +660,18 @@ Stream.prototype.resume = function () { }; -Stream.prototype.forceClose = function (exception) { +var forceCloseWarning; + +Stream.prototype.forceClose = function (e) { + if (!forceCloseWarning) { + forceCloseWarning = "forceClose() has been renamed to destroy()"; + sys.error(forceCloseWarning); + } + return this.destroy(e); +}; + + +Stream.prototype.destroy = function (exception) { // pool is shared between sockets, so don't need to free it here. var self = this; @@ -701,18 +712,27 @@ Stream.prototype._shutdown = function () { try { shutdown(this.fd, 'write') } catch (e) { - this.forceClose(e); + this.destroy(e); return; } - if (!this.readable) this.forceClose(); + if (!this.readable) this.destroy(); } }; +var closeDepricationWarning; Stream.prototype.close = function (data, encoding) { - if (data) this.write(data, encoding); + if (!closeDepricationWarning) { + closeDepricationWarning = "Notification: Stream.prototype.close has been renamed to end()"; + sys.error(closeDepricationWarning); + } + return this.end(data, encoding); +}; + +Stream.prototype.end = function (data, encoding) { if (this.writable) { + if (data) this.write(data, encoding); if (this._writeQueueLast() != END_OF_FILE) { this._writeQueue.push(END_OF_FILE); this.flush(); diff --git a/test/pummel/test-http-client-reconnect-bug.js b/test/pummel/test-http-client-reconnect-bug.js index bdc709d3563..2e963bb45a6 100644 --- a/test/pummel/test-http-client-reconnect-bug.js +++ b/test/pummel/test-http-client-reconnect-bug.js @@ -8,7 +8,7 @@ var errorCount = 0; var eofCount = 0; var server = tcp.createServer(function(socket) { - socket.close(); + socket.end(); }); server.listen(PORT); @@ -28,7 +28,7 @@ var request = client.request("GET", "/", {"host": "localhost"}); request.addListener('response', function(response) { sys.puts("STATUS: " + response.statusCode); }); -request.close(); +request.end(); setTimeout(function () { server.close(); diff --git a/test/pummel/test-keep-alive.js b/test/pummel/test-keep-alive.js index 5b71d4b00a4..cc81dfc8f17 100644 --- a/test/pummel/test-keep-alive.js +++ b/test/pummel/test-keep-alive.js @@ -10,7 +10,7 @@ server = http.createServer(function (req, res) { "Content-Type": "text/plain", }); res.write(body); - res.close(); + res.end(); }); server.listen(PORT); diff --git a/test/pummel/test-tcp-many-clients.js b/test/pummel/test-tcp-many-clients.js index 1c27169af4f..9ba72a74e3c 100644 --- a/test/pummel/test-tcp-many-clients.js +++ b/test/pummel/test-tcp-many-clients.js @@ -18,7 +18,7 @@ var server = net.createServer(function (c) { total_connections++; print("#"); c.write(body); - c.close(); + c.end(); }); }); server.listen(PORT); @@ -41,7 +41,7 @@ function runClient (callback) { }); client.addListener("end", function () { - client.close(); + client.end(); }); client.addListener("error", function (e) { diff --git a/test/pummel/test-tcp-pause.js b/test/pummel/test-tcp-pause.js index adb61544013..de84c0ee67c 100644 --- a/test/pummel/test-tcp-pause.js +++ b/test/pummel/test-tcp-pause.js @@ -5,7 +5,7 @@ N = 200; server = net.createServer(function (connection) { function write (j) { if (j >= N) { - connection.close(); + connection.end(); return; } setTimeout(function () { @@ -58,7 +58,7 @@ setTimeout(function () { client.addListener("end", function () { server.close(); - client.close(); + client.end(); }); process.addListener("exit", function () { diff --git a/test/pummel/test-tcp-pingpong-delay.js b/test/pummel/test-tcp-pingpong-delay.js index a2015c373e7..58546745f6d 100644 --- a/test/pummel/test-tcp-pingpong-delay.js +++ b/test/pummel/test-tcp-pingpong-delay.js @@ -8,7 +8,7 @@ function pingPongTest (port, host, on_complete) { var N = 100; var DELAY = 1; var count = 0; - var client_closed = false; + var client_ended = false; var server = net.createServer(function (socket) { socket.setEncoding("utf8"); @@ -32,11 +32,11 @@ function pingPongTest (port, host, on_complete) { socket.addListener("end", function () { puts("server-side socket EOF"); assert.equal("writeOnly", socket.readyState); - socket.close(); + socket.end(); }); socket.addListener("close", function (had_error) { - puts("server-side socket close"); + puts("server-side socket.end"); assert.equal(false, had_error); assert.equal("closed", socket.readyState); socket.server.close(); @@ -64,8 +64,8 @@ function pingPongTest (port, host, on_complete) { client.write("PING"); } else { puts("closing client"); - client.close(); - client_closed = true; + client.end(); + client_ended = true; } }, DELAY); }); @@ -76,9 +76,9 @@ function pingPongTest (port, host, on_complete) { }); client.addListener("close", function () { - puts("client close"); + puts("client.end"); assert.equal(N+1, count); - assert.equal(true, client_closed); + assert.ok(client_ended); if (on_complete) on_complete(); tests_run += 1; }); diff --git a/test/pummel/test-tcp-pingpong.js b/test/pummel/test-tcp-pingpong.js index c9a66ffc912..d96e398aeef 100644 --- a/test/pummel/test-tcp-pingpong.js +++ b/test/pummel/test-tcp-pingpong.js @@ -33,7 +33,7 @@ function pingPongTest (port, host, on_complete) { socket.addListener("end", function () { assert.equal("writeOnly", socket.readyState); - socket.close(); + socket.end(); }); socket.addListener("close", function (had_error) { @@ -71,7 +71,7 @@ function pingPongTest (port, host, on_complete) { } else { sent_final_ping = true; client.write("PING"); - client.close(); + client.end(); } }); diff --git a/test/pummel/test-tcp-throttle.js b/test/pummel/test-tcp-throttle.js index 029d3645726..8da7239d531 100644 --- a/test/pummel/test-tcp-throttle.js +++ b/test/pummel/test-tcp-throttle.js @@ -13,7 +13,7 @@ puts("start server on port " + PORT); server = net.createServer(function (connection) { connection.addListener("connect", function () { assert.equal(false, connection.write(body)); - connection.close(); + connection.end(); }); }); server.listen(PORT); @@ -46,7 +46,7 @@ client.addListener("data", function (d) { client.addListener("end", function () { server.close(); - client.close(); + client.end(); }); process.addListener("exit", function () { diff --git a/test/pummel/test-tcp-timeout.js b/test/pummel/test-tcp-timeout.js index fe82ab3d3f2..4279daf5ce6 100644 --- a/test/pummel/test-tcp-timeout.js +++ b/test/pummel/test-tcp-timeout.js @@ -20,7 +20,7 @@ var echo_server = net.createServer(function (socket) { }); socket.addListener("end", function () { - socket.close(); + socket.end(); }); }); @@ -58,7 +58,7 @@ client.addListener("timeout", function () { client.addListener("end", function () { puts("client end"); - client.close(); + client.end(); }); client.addListener("close", function () { diff --git a/test/pummel/test-tcp-tls.js b/test/pummel/test-tcp-tls.js index 55612d6965c..d156b936c76 100644 --- a/test/pummel/test-tcp-tls.js +++ b/test/pummel/test-tcp-tls.js @@ -37,7 +37,7 @@ function tlsTest (port, host, caPem, keyPem, certPem) { socket.addListener("end", function () { assert.equal("writeOnly", socket.readyState); - socket.close(); + socket.end(); }); socket.addListener("close", function (had_error) { @@ -83,7 +83,7 @@ function tlsTest (port, host, caPem, keyPem, certPem) { } else { sent_final_ping = true; client.write("PING"); - client.close(); + client.end(); } }); diff --git a/test/simple/test-child-process-ipc.js b/test/simple/test-child-process-ipc.js index ca28462aa7b..3b9881262ea 100644 --- a/test/simple/test-child-process-ipc.js +++ b/test/simple/test-child-process-ipc.js @@ -26,7 +26,7 @@ child.stdout.addListener("data", function (data){ } else { assert.equal("echo me\r\n", data); gotEcho = true; - child.stdin.close(); + child.stdin.end(); } }); diff --git a/test/simple/test-child-process-stdin.js b/test/simple/test-child-process-stdin.js index d60740cb715..6521f437682 100644 --- a/test/simple/test-child-process-stdin.js +++ b/test/simple/test-child-process-stdin.js @@ -6,7 +6,7 @@ var cat = spawn("cat"); cat.stdin.write("hello"); cat.stdin.write(" "); cat.stdin.write("world"); -cat.stdin.close(); +cat.stdin.end(); var response = ""; var exitStatus = -1; diff --git a/test/simple/test-file-read-stream.js b/test/simple/test-file-read-stream.js index de8ff632597..a7fa8b69ab7 100644 --- a/test/simple/test-file-read-stream.js +++ b/test/simple/test-file-read-stream.js @@ -10,7 +10,7 @@ var open: -1, end: -1, close: -1, - forceClose: -1 + destroy: -1 }, paused = false, @@ -51,9 +51,9 @@ file }); var file2 = fs.createReadStream(fn); -file2.forceClose(function(err) { +file2.destroy(function(err) { assert.ok(!err); - callbacks.forceClose++; + callbacks.destroy++; }); process.addListener('exit', function() { diff --git a/test/simple/test-file-write-stream.js b/test/simple/test-file-write-stream.js index df045998cd7..51beb8c8fe7 100644 --- a/test/simple/test-file-write-stream.js +++ b/test/simple/test-file-write-stream.js @@ -12,7 +12,7 @@ var open: -1, drain: -2, close: -1, - closeCb: -1, + endCb: -1, write: -11, }; @@ -31,9 +31,9 @@ file file.write(EXPECTED); } else if (callbacks.drain == 0) { assert.equal(EXPECTED+EXPECTED, fs.readFileSync(fn)); - file.close(function(err) { + file.end(function(err) { assert.ok(!err); - callbacks.closeCb++; + callbacks.endCb++; }); } }) diff --git a/test/simple/test-http-1.0.js b/test/simple/test-http-1.0.js index 3a8cd0ebb82..248c7fc5021 100644 --- a/test/simple/test-http-1.0.js +++ b/test/simple/test-http-1.0.js @@ -8,7 +8,7 @@ var client_got_eof = false; var server = http.createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"}); - res.close(body); + res.end(body); }) server.listen(PORT); @@ -27,7 +27,7 @@ c.addListener("data", function (chunk) { c.addListener("end", function () { client_got_eof = true; - c.close(); + c.end(); server.close(); }); diff --git a/test/simple/test-http-cat.js b/test/simple/test-http-cat.js index f270ca92782..179298e6aaf 100644 --- a/test/simple/test-http-cat.js +++ b/test/simple/test-http-cat.js @@ -8,7 +8,7 @@ var server = http.createServer(function (req, res) { ["Content-Length", body.length], ["Content-Type", "text/plain"] ]); - res.close(body); + res.end(body); }); server.listen(PORT); diff --git a/test/simple/test-http-chunked.js b/test/simple/test-http-chunked.js index bb065de938b..b1168ebb615 100644 --- a/test/simple/test-http-chunked.js +++ b/test/simple/test-http-chunked.js @@ -5,7 +5,7 @@ var UTF8_STRING = "南越国是前203年至前111年存在于岭南地区的一 var server = http.createServer(function(req, res) { res.writeHead(200, {"Content-Type": "text/plain; charset=utf8"}); - res.close(UTF8_STRING, 'utf8'); + res.end(UTF8_STRING, 'utf8'); }); server.listen(PORT); diff --git a/test/simple/test-http-client-race.js b/test/simple/test-http-client-race.js index b9b0df48487..e66964885c8 100644 --- a/test/simple/test-http-client-race.js +++ b/test/simple/test-http-client-race.js @@ -10,7 +10,7 @@ var server = http.createServer(function (req, res) { res.writeHead(200, { "Content-Type": "text/plain" , "Content-Length": body.length }); - res.close(body); + res.end(body); }); server.listen(PORT); @@ -34,10 +34,10 @@ req1.addListener('response', function (res1) { res2.addListener('data', function (chunk) { body2 += chunk; }); res2.addListener('end', function () { server.close(); }); }); - req2.close(); + req2.end(); }); }); -req1.close(); +req1.end(); process.addListener("exit", function () { assert.equal(body1_s, body1); diff --git a/test/simple/test-http-client-upload.js b/test/simple/test-http-client-upload.js index b4c0f61acba..ce7887a7ce8 100644 --- a/test/simple/test-http-client-upload.js +++ b/test/simple/test-http-client-upload.js @@ -19,7 +19,7 @@ var server = http.createServer(function(req, res) { puts("request complete from server"); res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('hello\n'); - res.close(); + res.end(); }); }); server.listen(PORT); @@ -42,7 +42,7 @@ req.addListener('response', function(res) { server.close(); }); }); -req.close(); +req.end(); process.addListener("exit", function () { assert.equal("1\n2\n3\n", sent_body); diff --git a/test/simple/test-http-malformed-request.js b/test/simple/test-http-malformed-request.js index 47bcfca3249..e93fba9037c 100644 --- a/test/simple/test-http-malformed-request.js +++ b/test/simple/test-http-malformed-request.js @@ -14,7 +14,7 @@ var s = http.createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("Hello World"); - res.close(); + res.end(); if (++nrequests_completed == nrequests_expected) s.close(); }); @@ -23,7 +23,7 @@ s.listen(PORT); var c = net.createConnection(PORT); c.addListener("connect", function () { c.write("GET /hello?foo=%99bar HTTP/1.1\r\n\r\n"); - c.close(); + c.end(); }); // TODO add more! diff --git a/test/simple/test-http-proxy.js b/test/simple/test-http-proxy.js index 348851d6bab..ffaec764eb1 100644 --- a/test/simple/test-http-proxy.js +++ b/test/simple/test-http-proxy.js @@ -9,7 +9,7 @@ var backend = http.createServer(function (req, res) { debug("backend request"); res.writeHead(200, {"content-type": "text/plain"}); res.write("hello world\n"); - res.close(); + res.end(); }); debug("listen backend") backend.listen(BACKEND_PORT); @@ -24,11 +24,11 @@ var proxy = http.createServer(function (req, res) { res.write(chunk); }); proxy_res.addListener("end", function() { - res.close(); + res.end(); debug("proxy res"); }); }); - proxy_req.close(); + proxy_req.end(); }); debug("listen proxy") proxy.listen(PROXY_PORT); @@ -54,7 +54,7 @@ function startReq () { debug("closed both"); }); }); - req.close(); + req.end(); } proxy.addListener('listening', startReq); diff --git a/test/simple/test-http-server.js b/test/simple/test-http-server.js index c7deeb8baff..ec249570ef3 100644 --- a/test/simple/test-http-server.js +++ b/test/simple/test-http-server.js @@ -38,7 +38,7 @@ http.createServer(function (req, res) { setTimeout(function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write(url.parse(req.url).pathname); - res.close(); + res.end(); }, 1); }).listen(PORT); @@ -63,7 +63,7 @@ c.addListener("data", function (chunk) { if (requests_sent == 2) { c.write("GET / HTTP/1.1\r\nX-X: foo\r\n\r\n" +"GET / HTTP/1.1\r\nX-X: bar\r\n\r\n"); - c.close(); + c.end(); assert.equal(c.readyState, "readOnly"); requests_sent += 2; } diff --git a/test/simple/test-http-tls.js b/test/simple/test-http-tls.js index 07848294215..92181332af2 100644 --- a/test/simple/test-http-tls.js +++ b/test/simple/test-http-tls.js @@ -54,7 +54,7 @@ var http_server=http.createServer(function (req, res) { req.addListener('end', function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("The path was " + url.parse(req.url).pathname); - res.close(); + res.end(); responses_sent += 1; }); @@ -78,7 +78,7 @@ req.addListener('response', function (res) { res.addListener('data', function (chunk) { body0 += chunk; }); debug("Got /hello response"); }); -req.close(); +req.end(); setTimeout(function () { req = client.request("POST", "/world"); @@ -94,7 +94,7 @@ setTimeout(function () { res.addListener('data', function (chunk) { body1 += chunk; }); debug("Got /world response"); }); - req.close(); + req.end(); }, 1); process.addListener("exit", function () { diff --git a/test/simple/test-http-wget.js b/test/simple/test-http-wget.js index 1d7f3412630..47e215e1ddb 100644 --- a/test/simple/test-http-wget.js +++ b/test/simple/test-http-wget.js @@ -25,7 +25,7 @@ var server = http.createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("hello "); res.write("world\n"); - res.close(); + res.end(); }) server.listen(PORT); @@ -46,7 +46,7 @@ c.addListener("data", function (chunk) { c.addListener("end", function () { client_got_eof = true; puts('got end'); - c.close(); + c.end(); }); c.addListener("close", function () { diff --git a/test/simple/test-http.js b/test/simple/test-http.js index c59927763ab..f1da37c7ca3 100644 --- a/test/simple/test-http.js +++ b/test/simple/test-http.js @@ -29,7 +29,7 @@ http.createServer(function (req, res) { req.addListener('end', function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("The path was " + url.parse(req.url).pathname); - res.close(); + res.end(); responses_sent += 1; }); @@ -45,7 +45,7 @@ req.addListener('response', function (res) { res.addListener('data', function (chunk) { body0 += chunk; }); debug("Got /hello response"); }); -req.close(); +req.end(); setTimeout(function () { req = client.request("POST", "/world"); @@ -56,7 +56,7 @@ setTimeout(function () { res.addListener('data', function (chunk) { body1 += chunk; }); debug("Got /world response"); }); - req.close(); + req.end(); }, 1); process.addListener("exit", function () { diff --git a/test/simple/test-net-pingpong.js b/test/simple/test-net-pingpong.js index ed8cfebf877..cf977dc248f 100644 --- a/test/simple/test-net-pingpong.js +++ b/test/simple/test-net-pingpong.js @@ -30,7 +30,7 @@ function pingPongTest (port, host) { socket.addListener("end", function () { assert.equal(true, socket.writable); assert.equal(false, socket.readable); - socket.close(); + socket.end(); }); socket.addListener("error", function (e) { @@ -38,7 +38,7 @@ function pingPongTest (port, host) { }); socket.addListener("close", function () { - puts('server socket closed'); + puts('server socket.endd'); assert.equal(false, socket.writable); assert.equal(false, socket.readable); socket.server.close(); @@ -77,12 +77,12 @@ function pingPongTest (port, host) { } else { sent_final_ping = true; client.write("PING"); - client.close(); + client.end(); } }); client.addListener("close", function () { - puts('client closed'); + puts('client.endd'); assert.equal(N+1, count); assert.equal(true, sent_final_ping); tests_run += 1; diff --git a/test/simple/test-remote-module-loading.js b/test/simple/test-remote-module-loading.js index 0a2af87e087..00a0974dccb 100644 --- a/test/simple/test-remote-module-loading.js +++ b/test/simple/test-remote-module-loading.js @@ -12,7 +12,7 @@ var server = http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/javascript'}); res.write(body); - res.close(); + res.end(); }); server.listen(PORT); diff --git a/test/simple/test-tcp-binary.js b/test/simple/test-tcp-binary.js index e1d85542c39..9dc347a4291 100644 --- a/test/simple/test-tcp-binary.js +++ b/test/simple/test-tcp-binary.js @@ -25,7 +25,7 @@ var echoServer = tcp.createServer(function (connection) { connection.write(chunk, "binary"); }); connection.addListener("end", function () { - connection.close(); + connection.end(); }); }); echoServer.listen(PORT); @@ -42,7 +42,7 @@ c.addListener("data", function (chunk) { c.write(String.fromCharCode(j), "binary"); j++; } else { - c.close(); + c.end(); } recv += chunk; }); diff --git a/test/simple/test-tcp-reconnect.js b/test/simple/test-tcp-reconnect.js index 66d93e30d63..143c4ac8b40 100644 --- a/test/simple/test-tcp-reconnect.js +++ b/test/simple/test-tcp-reconnect.js @@ -12,7 +12,7 @@ var server = net.createServer(function (socket) { }); socket.addListener("end", function () { - socket.close(); + socket.end(); }); socket.addListener("close", function (had_error) { @@ -37,7 +37,7 @@ server.addListener('listening', function () { client_recv_count += 1; puts("client_recv_count " + client_recv_count); assert.equal("hello\r\n", chunk); - client.close(); + client.end(); }); client.addListener("close", function (had_error) { From 1a9c9b0c55544d024796baf27e519880f365e9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 8 Apr 2010 22:07:14 +0200 Subject: [PATCH 44/73] Bring back the old manual style This brings back the old manual style, including the toc and syntax highlighting. --- Makefile | 4 +- doc/api_footer.html | 2 + doc/api_header.html | 20 ++++++ doc/doc.js | 15 +++++ doc/jquery.js | 154 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 doc/api_footer.html create mode 100644 doc/api_header.html create mode 100644 doc/doc.js create mode 100644 doc/jquery.js diff --git a/Makefile b/Makefile index 5b154a96cff..36a518d0827 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,9 @@ benchmark: all doc: doc/node.1 doc/api.html doc/index.html doc/changelog.html doc/api.html: doc/api.markdown - ronn --html doc/api.markdown > doc/api.html + ronn -f --html doc/api.markdown \ + | sed "s/

\(.*\)<\/h2>/

\1<\/h2>/g" \ + | cat doc/api_header.html - doc/api_footer.html > doc/api.html doc/changelog.html: ChangeLog echo 'Node.js ChangeLog

Node.js ChangeLog

' > doc/changelog.html
diff --git a/doc/api_footer.html b/doc/api_footer.html
new file mode 100644
index 00000000000..691287b6e35
--- /dev/null
+++ b/doc/api_footer.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/doc/api_header.html b/doc/api_header.html
new file mode 100644
index 00000000000..43dbaeb679f
--- /dev/null
+++ b/doc/api_header.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+NODE(1)
+
+
+
+
+
+
+
+
+
+
+
Table of Contents
+ +
diff --git a/doc/doc.js b/doc/doc.js new file mode 100644 index 00000000000..aeb1669e35e --- /dev/null +++ b/doc/doc.js @@ -0,0 +1,15 @@ +$(function() { + var $toc = $('#toc'); + $('h2').each(function() { + var + $h2 = $(this), + $div = $('
'), + $a = $('') + .text($h2.text()) + .attr('href', '#'+$h2.attr('id')); + + $toc.append($div.append($a)); + }); + + sh_highlightDocument(); +}); \ No newline at end of file diff --git a/doc/jquery.js b/doc/jquery.js new file mode 100644 index 00000000000..7c243080233 --- /dev/null +++ b/doc/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); From b544185bd8838115981003d48b62591b4b3028e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Thu, 8 Apr 2010 22:29:39 +0200 Subject: [PATCH 45/73] Fix doc toc for small screens Only make the toc fixed position for big screens. --- doc/pipe.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/pipe.css b/doc/pipe.css index 123902ac2fe..1097ae896de 100644 --- a/doc/pipe.css +++ b/doc/pipe.css @@ -11,13 +11,14 @@ img { padding: 5em 0; } #toc { - position: fixed; + position: absolute; top: 2em; left: 0; width: 8em; font-size: 12pt; line-height: 150%; } +@media all and (min-height: 650px) { #toc { position: fixed; }} #toctitle { display: none; } From 499c615c9e5151bc5d85165c68122171ddfa9e7f Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 14:22:30 -0700 Subject: [PATCH 46/73] Doc changes for new API (part 1) --- doc/api.markdown | 726 ++++++++++++++++++++++++++--------------------- doc/index.html | 6 +- 2 files changed, 404 insertions(+), 328 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index 10f3f5cc773..3fc5028b6a2 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1,22 +1,21 @@ node(1) -- evented I/O for V8 JavaScript ======================================== -## SYNOPSIS +## Synopsis An example of a web server written with Node which responds with "Hello -World": +World": var sys = require("sys"), http = require("http"); - + http.createServer(function (request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); - response.write("Hello World\n"); - response.close(); + response.end("Hello World\n"); }).listen(8000); - + sys.puts("Server running at http://127.0.0.1:8000/"); To run the server, put the code into a file called `example.js` and execute @@ -28,109 +27,326 @@ it with the node program All of the examples in the documentation can be run similarly. -## ENCODINGS +## String Encodings and Buffers + +Pure Javascript is Unicode friendly but not nice to pure binary data. When +dealing with TCP streams or the file system, it's necessary to handle octet +streams. Node has several stratagies for manipulating, creating, and +consuming octet streams. + +Raw data is stored in instaces of the `Buffer` class. A `Buffer` is similar +to an array of integers but correspond to a raw memory allocation outside +the V8 heap. A `Buffer` cannot be resized. +Access the class at `require('buffer').Buffer`. + +- **`new Buffer(size)`**: Allocates a new buffer of `size` octets. + +- **`buffer[index]`**: Get and set the octet at `index`. The value can be +between 0x00 and 0xFF. + +- **`buffer.length`**: length in octets. + +- **`buffer.copy(targetBuffer, targetStart, start, end)`**: +Does a memcpy() between buffers. + +- **`buffer.slice(start, end)`**: Returns a new buffer which references the +same memory as the old, but offset and cropped by the `start` and `end` +indexes. **Modifying the new buffer slice will modify memory in the original +buffer!** Node supports 3 string encodings. UTF-8 (`"utf8"`), ASCII (`"ascii"`), and Binary (`"binary"`). `"ascii"` and `"binary"` only look at the first 8 bits -of the 16bit JavaScript string characters. Both are relatively fast--use -them if you can. `"utf8"` is slower and should be avoided when possible. +of the 16bit JavaScript string characters. The following `Buffer` methods +allow decoding and encoding of strings: + +- **`buffer.utf8Write(string, offset)`**: Writes `string` to the buffer at +`offset` using UTF-8 encoding. Returns the number of octets written. If +`buffer` did not contain enough space to fit the entire string it will write +a partial amount of the string. However, this method will not write partial +characters. + +- **`buffer.binaryWrite(string, offset)`**: Writes `string` to the buffer at +`offset` using binary encoding - that is it will only use the first 8 bits +of each character. Write a partial string if not enough space remains. +Returns number of octets written. + +- **`buffer.asciiWrite(string, offset)`**: Writes `string` to the buffer at +`offset` using ASCII encoding. Faster than `utf8Write()`. Write a partial +string if not enough space remains. Returns number of octets written. + +- **`buffer.utf8Slice(start, end)`**: Decodes and returns a string assuming +UTF-8 encoding beginning at `start` and ending at `end`. + +- **`buffer.binarySlice(start, end)`**: Decodes and returns a string assuming +binary encoding beginning at `start` and ending at `end`. + +- **`buffer.asciiSlice(start, end)`**: Decodes and returns a string assuming +ASCII encoding beginning at `start` and ending at `end`. -## GLOBAL OBJECTS + +## Events + +Many objects in Node emit events: a TCP server emits an event each time +there is a stream, a child process emits an event when it exits. All +objects which emit events are instances of `events.EventEmitter`. + +Events are represented by a camel-cased string. Here are some examples: +`"stream"`, `"data"`, `"messageBegin"`. + +Functions can be then be attached to objects, to be executed when an event +is emitted. These functions are called _listeners_. + + +### events.EventEmitter + +`require("events")` to access the events module. + +All EventEmitters emit the event `"newListener"` when new listeners are +added. + +- **`"newListener"`** - `callback(event, listener)`: +This event is made any time someone adds a new listener. + + +### emitter.addListener(event, listener) + +Adds a listener to the end of the listeners array for the specified event. + + server.addListener('stream', function (stream) { + sys.puts("someone connected!"); + }); + + +### emitter.removeListener(event, listener) + +Remove a listener from the listener array for the specified event. +**Caution**: changes array indices in the listener array behind the listener. + + +### emitter.removeAllListeners(event) + +Removes all listeners from the listener array for the specified event. + + +### emitter.listeners(event) + +Returns an array of listeners for the specified event. This array can be +manipulated, e.g. to remove listeners. + + +### emitter.emit(event, arg1, arg2, ...) + +Execute each of the listeners in order with the supplied arguments. + + + +## Streams + +A stream is an abstract interface implemented by various objects in Node. +For example a request to an HTTP server is a stream, as is stdout. Streams +are readable, writable, or both. All streams are instances of `EventEmitter`. + +### Readable Stream + +A **readable stream** has the following methods, members, and events. + +- **`stream.addListener('data', function (data) { ... })`**: +The `'data'` event emits either a `Buffer` (by default) or a string if +`setEncoding()` was used. + +- **`stream.addListener('end', function () { ... })`**: +Emitted when the stream has received an EOF (FIN in TCP terminology). +Indicates that no more `'data'` events will happen. If the stream is also +writable, it may be possible to continue writing. + +- **`stream.addListener('error', function (exception) { ... })`**: +Emitted if there was an error receiving data. + +- **`stream.addListener('close', function () { ... })`**: +Emitted when the underlying file descriptor has be closed. Not all streams +will emit this. (For example, an incoming HTTP request will not emit +`'close'`.) + +- **`stream.setEncoding(encoding)`**: +Makes the data event emit a string instead of a `Buffer`. `encoding` can be +`'utf8'`, `'ascii'`, or `'binary'`. + +- **`stream.pause()`**: +Pauses the incoming `'data'` events. + +- **`stream.resume()`**: +Resumes the incoming `'data'` events after a `pause()`. + +- **`stream.destroy()`**: +Closes the underlying file descriptor. Stream will not emit any more events. + +### Writable Stream + +A **writable stream** has the following methods, members, and events. + +- **`stream.addListener('drain', function () { ... })`**: +Emitted after a `write()` method was called that returned `false` to +indicate that it is safe to write again. + +- **`stream.addListener('error', function (e) { ... })`**: +Emitted on error with the exception `e`. + +- **`stream.addListener('close', function () { ... })`**: +Emitted when the underlying file descriptor has been closed. + +- **`stream.write(string, encoding)`**: +Writes `string` with the given `encoding` to the stream. Returns `true` if +the string has been flushed to the kernel buffer. Returns `false` to +indicate that the kernel buffer is full, and the data will be sent out in +the future. The `'drain'` event will indicate when the kernel buffer is +empty again. The `encoding` defaults to `'utf8'`. + + +- **`stream.write(buffer)`**: +Same as the above except with a raw buffer. + +- **`stream.end()`**: +Terminates the stream with EOF or FIN. + +- **`stream.end(string, encoding)`**: +Sends `string` with the given `encoding` and terminates the stream with EOF +or FIN. This is useful to reduce the number of packets sent. + +- **`stream.end(buffer)`**: +Same as above but with a `buffer`. + +- **`stream.destroy()`**: +Closes the underlying file descriptor. Stream will not emit any more events. + + +## Global Objects These object are available in the global scope and can be accessed from anywhere. - - **`global`**: The global namespace object. +- **`global`**: The global namespace object. - - **`process`**: The process object. Most stuff lives in here. See the "process +- **`process`**: The process object. Most stuff lives in here. See the "process object" section. - - **`require()`**: See the modules section. +- **`require()`**: See the modules section. - - **`require.paths`**: The search path for absolute path arguments to `require()`. +- **`require.paths`**: The search path for absolute path arguments to `require()`. - - **`__filename`**: The filename of the script being executed. +- **`__filename`**: The filename of the script being executed. - - **`__dirname`**: The dirname of the script being executed. +- **`__dirname`**: The dirname of the script being executed. - - **`module`**: A reference to the current module (of type `process.Module`). In particular `module.exports` is the same as the `exports` object. See `src/process.js` for more information. +- **`module`**: A reference to the current module (of type +`process.Module`). In particular `module.exports` is the same as the +`exports` object. See `src/process.js` for more information. -## PROCESS OBJECT +## process The `process` object is a global object and can be accessed from anywhere. It is an instance of `EventEmitter` and has the following events: - - **`"exit"`** - `callback()`: - Made when the process is about to exit. - This is a good hook to perform constant time checks of the module's state (like for unit tests). - The main event loop will no longer be run after the "exit" callback finishes, so timers may not - be scheduled. - - **`"uncaughtException"`** - `callback(exception)`: - Emitted when an exception bubbles all the way back to the event loop. If a - listener is added for this exception, the default action (which is to - print a stack trace and exit) will not occur. +### process.addListener('exit', function () { ... }) - - `"SIGINT", "SIGHUP", ... - callback()`: - Emitted when the processes receives a signal. See sigaction(2) for a list - of standard POSIX signal names such as SIGINT, SIGUSR1, etc. +Emitted when the process is about to exit. This is a good hook to perform +constant time checks of the module's state (like for unit tests). The main +event loop will no longer be run after the "exit" callback finishes, so +timers may not be scheduled. Example of listening for `exit`: var sys = require('sys'); - process.addListener("exit", function () { + process.addListener('exit', function () { process.nextTick(function () { sys.puts("This will not run"); }); - sys.puts("About to exit."); }); +### process.addListener('uncaughtException', function (err) { ... }) + +Emitted when an exception bubbles all the way back to the event loop. If a +listener is added for this exception, the default action (which is to print +a stack trace and exit) will not occur. Example of listening for `uncaughtException`: var sys = require("sys"); - process.addListener("uncaughtException", function (exception) { - if (exception.type === 'not_defined') { - sys.puts("Caught exception: " + exception); - } - else { - throw(exception); - } + process.addListener('uncaughtException', function (err) { + sys.puts("Caught exception: " + err); }); setTimeout(function () { sys.puts("This will still run."); }, 500); - bad_func(); // Intentionally cause an exception, but don't catch it. + // Intentionally cause an exception, but don't catch it. + nonexistantFunc(); sys.puts("This will not run."); -Note that `uncaughtException` is a very crude mechanism for exception handling. Using -try / catch in your program will give you more control over your program's flow. -Especially for server programs that are designed to stay running forever, `uncaughtException` -can be a useful safety mechanism. +Note that `uncaughtException` is a very crude mechanism for exception +handling. Using try / catch in your program will give you more control over +your program's flow. Especially for server programs that are designed to +stay running forever, `uncaughtException` can be a useful safety mechanism. +### process.addListener('SIGINT', function () { ... }) + +Emitted when the processes receives a signal. See sigaction(2) for a list of +standard POSIX signal names such as SIGINT, SIGUSR1, etc. + Example of listening for `SIGINT`: var sys = require("sys"), stdin = process.openStdin(); - process.addListener("SIGINT", function () { + process.addListener('SIGINT', function () { sys.puts("Got SIGINT. Press Control-D to exit."); }); -An easy way to send the `SIGINT` signal is with `Control-C` in most terminal programs. +An easy way to send the `SIGINT` signal is with `Control-C` in most terminal +programs. - -### process.argv, process.ARGV +### process.stdout -An array containing the command line arguments. The first element will be 'node', the second element -will be the name of the JavaScript file. The next elements will be any additional command line arguments. +A writable stream to `stdout`. + +Example: the definition of `sys.puts` + + exports.puts = function (d) { + process.stdout.write(d + '\n'); + }; + + + +### process.openStdin() + +Opens the standard input stream, returns a readable stream. + +Example of opening standard input and listening for both events: + + var stdin = process.openStdin(); + + stdin.setEncoding('utf8'); + + stdin.addListener('data', function (chunk) { + process.stdout.write("data: " + chunk); + }); + + stdin.addListener('end', function () { + process.stdout.write("end"); + }); + + +### process.argv + +An array containing the command line arguments. The first element will be +'node', the second element will be the name of the JavaScript file. The +next elements will be any additional command line arguments. // print process.argv var sys = require("sys"); @@ -141,14 +357,13 @@ will be the name of the JavaScript file. The next elements will be any addition This will generate: - mjr-mbp:~/work/node_docs/data/v0.1.31/examples$ node process-2.js one two=three four + $ node process-2.js one two=three four 0: node 1: /Users/mjr/work/node_docs/data/v0.1.31/examples/process-2.js 2: one 3: two=three 4: four - -Note that `process.argv` and `process.ARGV` are equivalent. + ### process.chdir(directory) @@ -178,7 +393,7 @@ Example of using `process.compile` and `eval` to run the same code: var sys = require("sys"), localVar = 123, compiled, evaled; - + compiled = process.compile("localVar = 1;", "myfile.js"); sys.puts("localVar: " + localVar + ", compiled: " + compiled); evaled = eval("localVar = 1;"); @@ -200,7 +415,7 @@ Returns the current working directory of the process. require('sys').puts("Current directory: " + process.cwd()); -### process.env, process.ENV +### process.env An object containing the user environment. See environ(7). @@ -211,7 +426,6 @@ An object containing the user environment. See environ(7). sys.puts(index + ": " + val + "=" + process.env[val]); }); -Note that `process.env` and `process.ENV` are equivalent. ### process.evalcx(code, sandbox, filename) @@ -225,7 +439,7 @@ as if it were loaded from `filename`. The object `sandbox` will be used as the animal: "cat", count: 2 }; - + process.evalcx('count += 1; name = "kitty"', sandbox, "myfile.js"); sys.puts(sys.inspect(sandbox)); @@ -268,7 +482,7 @@ Gets/sets the group identity of the process. (See setgid(2).) This is the numer Gets/sets the user identity of the process. (See setuid(2).) This is the numerical userid, not the username. var sys = require('sys'); - + sys.puts("Current uid: " + process.getuid()); try { process.setuid(501); @@ -290,7 +504,7 @@ A compiled-in property that exposes `NODE_PREFIX`. Send a signal to a process. `pid` is the process id and `signal` is the string describing the signal to send. Signal names are strings like -"SIGINT" or "SIGUSR1". If omitted, the signal will be "SIGINT". +"SIGINT" or "SIGUSR1". If omitted, the signal will be "SIGINT". See kill(2) for more information. Note that just because the name of this function is `process.kill`, it is @@ -301,7 +515,7 @@ Example of sending a signal to yourself: var sys = require("sys"); - process.addListener("SIGHUP", function () { + process.addListener('SIGHUP', function () { sys.puts("Got SIGHUP signal."); }); @@ -350,7 +564,7 @@ This will generate: On the next loop around the event loop call this callback. This is *not* a simple alias to `setTimeout(fn, 0)`, it's much more -efficient. +efficient. var sys = require("sys"); @@ -374,7 +588,7 @@ given, otherwise returns the current mask. -## SYSTEM MODULE +## sys These functions are in the module `"sys"`. Use `require("sys")` to access them. @@ -430,98 +644,11 @@ Example of inspecting all properties of the `sys` object: -## EVENTS - -Many objects in Node emit events: a TCP server emits an event each time -there is a connection, a child process emits an event when it exits. All -objects which emit events are instances of `events.EventEmitter`. - -Events are represented by a camel-cased string. Here are some examples: -`"connection"`, `"data"`, `"messageBegin"`. - -Functions can be then be attached to objects, to be executed when an event -is emitted. These functions are called _listeners_. - - -### events.EventEmitter - -`require("events")` to access the events module. - -All EventEmitters emit the event `"newListener"` when new listeners are -added. - -- **`"newListener"`** - `callback(event, listener)`: -This event is made any time someone adds a new listener. - - -### emitter.addListener(event, listener) - -Adds a listener to the end of the listeners array for the specified event. - - server.addListener("connection", function (socket) { - sys.puts("someone connected!"); - }); - - -### emitter.removeListener(event, listener) - -Remove a listener from the listener array for the specified event. -**Caution**: changes array indices in the listener array behind the listener. - - -### emitter.removeAllListeners(event) - -Removes all listeners from the listener array for the specified event. - - -### emitter.listeners(event) - -Returns an array of listeners for the specified event. This array can be -manipulated, e.g. to remove listeners. - - -### emitter.emit(event, arg1, arg2, ...) - -Execute each of the listeners in order with the supplied arguments. -## STANDARD I/O -Writing data to standard output is typically done with the output functions in the `sys` module. - -The underlying `net.Stream` object associated with `stdout` and `stdin` is available via `process.stdout` -and `process.stdin`. To read from standard input, it must first be opened. See below. - - -### process.openStdin() - -Open stdin. The program will not exit until `process.stdin.close()` has been -called or the `"close"` event has been emitted. - -- **`"data"`** - `callback(data)`: -Emitted when stdin has received a chunk of data. - -- **`"close"`** - `callback()`: -Emitted when stdin has been closed. - - -Example of opening standard input and listening for both events: - - var sys = require("sys"), - stdin = process.openStdin(); - - stdin.addListener("data", function (chunk) { - sys.print("data: " + chunk); - }); - - stdin.addListener("end", function () { - sys.puts("end"); - }); - - - -## MODULES +## Modules Node uses the CommonJS module system. @@ -568,15 +695,10 @@ this: That is, when `require("assert")` is called Node looks for: - * 1: - `/home/ryan/.node_libraries/assert.js` - * 2: - `/home/ryan/.node_libraries/assert.node` - * 3: - `/home/ryan/.node_libraries/assert/index.js` - * 4: - `/home/ryan/.node_libraries/assert/index.node` - + * 1: `/home/ryan/.node_libraries/assert.js` + * 2: `/home/ryan/.node_libraries/assert.node` + * 3: `/home/ryan/.node_libraries/assert/index.js` + * 4: `/home/ryan/.node_libraries/assert/index.node` interrupting once a file is found. Files ending in `".node"` are binary Addon Modules; see the section below about addons. `"index.js"` allows one to @@ -591,7 +713,7 @@ Use `process.mixin()` to include modules into the global namespace. process.mixin(GLOBAL, require("./circle"), require("sys")); puts("The area of a circle of radius 4 is " + area(4)); -## TIMERS +## Timers ### setTimeout(callback, delay, [arg, ...]) @@ -657,7 +779,7 @@ Stops a interval from triggering. sys.puts("Started timer."); -## CHILD PROCESSES +## Child Processes Node provides a tri-directional `popen(3)` facility through the `ChildProcess` class. @@ -685,7 +807,7 @@ environmental variables. For example: // Pipe a child process output to // parent process output var ls = spawn("ls", ["-lh", "/usr"]); - ls.stdout.addListener("data", function (data) { + ls.stdout.addListener('data', function (data) { process.stdout.write(data); }); @@ -724,7 +846,7 @@ The callback gets the arguments `(err, stdout, stderr)`. On success +err+ will be `null`. On error `err` will be an instance of `Error` and `err.code` will be the exit code of the child process. -## FILE SYSTEM +## File System File I/O is provided by simple wrappers around standard POSIX functions. To use this module do `require("fs")`. All the methods have asynchronous and @@ -1031,7 +1153,7 @@ Returns a new FileReadStream object. ### readStream.readable A boolean that is `true` by default, but turns `false` after an `"error"` -occured, the stream came to an "end", or `forceClose()` was called. +occured, the stream came to an "end", or `destroy()` was called. ### readStream.pause() @@ -1042,7 +1164,7 @@ until the stream is resumed. Resumes the stream. Together with `pause()` this useful to throttle reading. -### readStream.forceClose([callback]) +### readStream.destroy() Allows to close the stream before the `"end"` is reached. No more events other than `"close"` will be fired after this method has been called. @@ -1067,9 +1189,9 @@ Returns a new FileWriteStream object. ### writeStream.writeable A boolean that is `true` by default, but turns `false` after an `"error"` -occurred or `close()` / `forceClose()` was called. +occurred or `end()` / `destroy()` was called. -### writeStream.write(data, [callback]) +### writeStream.write(data) Returns `true` if the data was flushed to the kernel, and `false` if it was queued up for being written later. A `"drain"` will fire after all queued data @@ -1078,11 +1200,11 @@ has been written. You can also specify `callback` to be notified when the data from this write has been flushed. The first param is `err`, the second is `bytesWritten`. -### writeStream.close([callback]) +### writeStream.end() Closes the stream right after all queued `write()` calls have finished. -### writeStream.forceClose([callback]) +### writeStream.destroy() Allows to close the stream regardless of its current state. @@ -1100,14 +1222,14 @@ HTTP message headers are represented by an object like this: { "content-length": "123" , "content-type": "text/plain" - , "connection": "keep-alive" + , "stream": "keep-alive" , "accept": "*/*" } Keys are lowercased. Values are not modified. In order to support the full spectrum of possible HTTP applications, Node's -HTTP API is very low-level. It deals with connection handling and message +HTTP API is very low-level. It deals with stream handling and message parsing only. It parses a message into headers and body but it does not parse the actual headers or the body. @@ -1120,11 +1242,11 @@ This is an EventEmitter with the following events: `request` is an instance of `http.ServerRequest` and `response` is an instance of `http.ServerResponse` - - **`"connection"`** - `callback(connection)`: - When a new TCP connection is established. - `connection` is an object of type `http.Connection`. Usually users - will not want to access this event. The `connection` can also be - accessed at `request.connection`. + - **`"stream"`** - `callback(stream)`: + When a new TCP stream is established. + `stream` is an object of type `http.Connection`. Usually users + will not want to access this event. The `stream` can also be + accessed at `request.stream`. - **`"close"`** - `callback(errno)`: Emitted when the server closes. `errorno` is an integer which indicates what, if any, @@ -1138,32 +1260,35 @@ Returns a new web server object. The `options` argument is optional. The `options` argument accepts the same values as the -options argument for `tcp.Server`. +options argument for `net.Server`. The `request_listener` is a function which is automatically added to the `"request"` event. -### server.setSecure(format_type, ca_certs, crl_list, private_key, certificate) - -Enable TLS for all incoming connections, with the specified credentials. - -`format_type` currently has to be "X509_PEM", and each of the ca, crl, key and -cert parameters are in the format of PEM strings. - -`ca_certs` is a string that holds a number of CA certificates for use in accepting client connections that authenticate themselves with a client certificate. - -`private_key` is a PEM string of the unencrypted key for the server. - ### server.listen(port, hostname) -Begin accepting connections on the specified port and hostname. -If the hostname is omitted, the server will accept connections -directed to any address. This function is synchronous. +Begin accepting connections on the specified port and hostname. If the +hostname is omitted, the server will accept connections directed to any +address. + +This function is asynchronous. `listening` will be emitted when the server +is ready to accept connections. + + +### server.listen(path) + +Start an HTTP UNIX socket server listening for connections on the given `path`. +(Hint: use NGINX to load balance across many Node servers with this.) + +This function is asynchronous. `listening` will be emitted when the server +is ready to accept connections. + ### server.close() Stops the server from accepting new connections. + ### http.ServerRequest This object is created internally by a HTTP server--not by @@ -1236,7 +1361,7 @@ The HTTP protocol version as a string. Read only. Examples: `"1.1"`, `"1.0"` -### request.setBodyEncoding(encoding="binary") +### request.setEncoding(encoding="binary") Set the encoding for the request body. Either `"utf8"` or `"binary"`. Defaults to `"binary"`. @@ -1251,7 +1376,7 @@ Pauses request from emitting events. Useful to throttle back an upload. Resumes a paused request. -### request.connection +### request.stream The `http.Connection` object. @@ -1276,7 +1401,7 @@ Example: }); This method must only be called once on a message and it must -be called before `response.close()` is called. +be called before `response.end()` is called. ### response.write(chunk, encoding="ascii") @@ -1298,11 +1423,11 @@ data, and sends that separately. That is, the response is buffered up to the first chunk of body. -### response.close() +### response.end() This method signals to the server that all of the response headers and body has been sent; that server should consider this message complete. -The method, `response.close()`, MUST be called on each +The method, `response.end()`, MUST be called on each response. ### http.Client @@ -1310,8 +1435,8 @@ response. An HTTP client is constructed with a server address as its argument, the returned handle is then used to issue one or more requests. Depending on the server connected to, the client might -pipeline the requests or reestablish the connection after each -connection. _Currently the implementation does not pipeline requests._ +pipeline the requests or reestablish the stream after each +stream. _Currently the implementation does not pipeline requests._ Example of connecting to `google.com`: @@ -1322,23 +1447,23 @@ Example of connecting to `google.com`: request.addListener('response', function (response) { sys.puts("STATUS: " + response.statusCode); sys.puts("HEADERS: " + JSON.stringify(response.headers)); - response.setBodyEncoding("utf8"); - response.addListener("data", function (chunk) { + response.setEncoding("utf8"); + response.addListener('data', function (chunk) { sys.puts("BODY: " + chunk); }); }); - request.close(); + request.end(); ### http.createClient(port, host) Constructs a new HTTP client. `port` and `host` refer to the server to be connected to. A -connection is not established until a request is issued. +stream is not established until a request is issued. ### client.request([method], path, [request_headers]) -Issues a request; if necessary establishes connection. Returns a `http.ClientRequest` instance. +Issues a request; if necessary establishes stream. Returns a `http.ClientRequest` instance. `method` is optional and defaults to "GET" if omitted. @@ -1350,22 +1475,11 @@ Do remember to include the `Content-Length` header if you plan on sending a body. If you plan on streaming the body, perhaps set `Transfer-Encoding: chunked`. -*NOTE*: the request is not complete. This method only sends -the header of the request. One needs to call -`request.close()` to finalize the request and retrieve -the response. (This sounds convoluted but it provides a chance -for the user to stream a body to the server with -`request.write()`.) +*NOTE*: the request is not complete. This method only sends the header of +the request. One needs to call `request.end()` to finalize the request and +retrieve the response. (This sounds convoluted but it provides a chance for +the user to stream a body to the server with `request.write()`.) -### client.setSecure(format_type, ca_certs, crl_list, private_key, certificate) - -Enable TLS for the client connection, with the specified credentials. - -`format_type` currently has to be "X509_PEM", and each of the ca, crl, key and -cert parameters are in the format of PEM strings, and optional. - -`ca_certs` is a string that holds a number of CA certificates for use in deciding the authenticity of the remote server. `private_key` is a PEM string of the unencrypted key for the client, which together with the certificate allows the client to authenticate -itself to the server. ### http.ClientRequest @@ -1389,7 +1503,7 @@ event, the entire body will be caught. // Good request.addListener('response', function (response) { - response.addListener("data", function (chunk) { + response.addListener('data', function (chunk) { sys.puts("BODY: " + chunk); }); }); @@ -1397,7 +1511,7 @@ event, the entire body will be caught. // Bad - misses all or part of the body request.addListener('response', function (response) { setTimeout(function () { - response.addListener("data", function (chunk) { + response.addListener('data', function (chunk) { sys.puts("BODY: " + chunk); }); }, 10); @@ -1427,10 +1541,10 @@ argument should be either `"utf8"` or `"ascii"`. By default the body uses ASCII encoding, as it is faster. -### request.close() +### request.end() Finishes sending the request. If any parts of the body are -unsent, it will flush them to the socket. If the request is +unsent, it will flush them to the stream. If the request is chunked, this will send the terminating `"0\r\n\r\n"`. @@ -1466,7 +1580,7 @@ The HTTP version of the connected-to server. Probably either The response headers. -### response.setBodyEncoding(encoding) +### response.setEncoding(encoding) Set the encoding for the response body. Either `"utf8"` or `"binary"`. Defaults to `"binary"`. @@ -1484,73 +1598,60 @@ Resumes a paused response. A reference to the `http.Client` that this response belongs to. -## TCP +## Networking -To use the TCP server and client one must `require("tcp")`. +Creating UNIX and TCP servers and clients. +To use networking, one must `require("net")`. -### tcp.Server +### net.Server Here is an example of a echo server which listens for connections on port 7000: - var tcp = require("tcp"); - var server = tcp.createServer(function (socket) { - socket.setEncoding("utf8"); - socket.addListener("connect", function () { - socket.write("hello\r\n"); + var net = require("net"); + var server = net.createServer(function (stream) { + stream.setEncoding("utf8"); + stream.addListener('connect', function () { + stream.write("hello\r\n"); }); - socket.addListener("data", function (data) { - socket.write(data); + stream.addListener('data', function (data) { + stream.write(data); }); - socket.addListener("end", function () { - socket.write("goodbye\r\n"); - socket.close(); + stream.addListener('end', function () { + stream.write("goodbye\r\n"); + stream.end(); }); }); server.listen(7000, "localhost"); This is an EventEmitter with the following events: -- **`"connection"`** - `callback(connection)`: -Emitted when a new connection is made. `connection` is an instance of `tcp.Connection`. +- **`"stream"`** - `callback(stream)`: +Emitted when a new stream is made. `stream` is an instance of `net.Stream`. - **`"close"`** - `callback(errno)`: Emitted when the server closes. `errorno` is an integer which indicates what, if any, error caused the server to close. If no error occurred `errorno` will be 0. -### tcp.createServer(connection_listener) +### net.createServer(connectionListener) Creates a new TCP server. The `connection_listener` argument is automatically set as a listener for -the `"connection"` event. +the `"stream"` event. -### server.setSecure(format_type, ca_certs, crl_list, private_key, certificate) -Enable TLS for all incoming connections, with the specified credentials. - -`format_type` currently has to be "X509_PEM", and each of the ca, crl, key and -cert parameters are in the format of PEM strings. - -`ca_certs` is a string that holds a number of CA certificates for use in -accepting client connections that authenticate themselves with a client -certificate. - -`private_key` is a PEM string of the unencrypted key for the server. - -### server.listen(port, host=null, backlog=128) +### server.listen(port, host=null) Tells the server to listen for TCP connections to `port` and `host`. `host` is optional. If `host` is not specified the server will accept client connections on any network address. -The third argument, `backlog`, is also optional and defaults to 128. The -`backlog` argument defines the maximum length to which the queue of pending -connections for the server may grow. +This function is asynchronous. The server will emit `'listening'` when it is +safe to connect to it. -This function is synchronous. ### server.close() @@ -1558,77 +1659,77 @@ Stops the server from accepting new connections. This function is asynchronous, the server is finally closed when the server emits a `"close"` event. -### tcp.Connection +### net.Stream -This object is used as a TCP client and also as a server-side -socket for `tcp.Server`. +This object is used as a TCP/UNIX client and also as a server-side stream +for `net.Server`. -This is an EventEmitter with the following events: +This is an EventEmitter and duplex stream with the following events: - **`"connect"`** - `callback()`: -Call once the connection is established after a call to -`createConnection()` or `connect()`. +Call once the stream is established after a call to `createConnection()` or +`connect()`. - **`"data"`** - `callback(data)`: -Called when data is received on the connection. `data` -will be a string. Encoding of data is set by `connection.setEncoding()`. +Called when data is received on the stream. `data` +will be a string. Encoding of data is set by `stream.setEncoding()`. - **`"end"`** - `callback()`: -Called when the other end of the connection sends a FIN +Called when the other end of the stream sends a FIN packet. After this is emitted the `readyState` will be `"writeOnly"`. One should probably just call -`connection.close()` when this event is emitted. +`stream.end()` when this event is emitted. - **`"timeout"`** - `callback()`: -Emitted if the connection times out from inactivity. The +Emitted if the stream times out from inactivity. The `"close"` event will be emitted immediately following this event. - **`"drain"`** - `callback()`: Emitted when the write buffer becomes empty. Can be used to throttle uploads. - **`"close"`** - `callback(had_error)`: -Emitted once the connection is fully closed. The argument `had_error` is a boolean which says if -the connection was closed due to a transmission +Emitted once the stream is fully closed. The argument `had_error` is a boolean which says if +the stream was closed due to a transmission error. (TODO: access error codes.) -### tcp.createConnection(port, host="127.0.0.1") +### net.createConnection(port, host="127.0.0.1") -Creates a new connection object and opens a connection to the specified `port` +Creates a new stream object and opens a stream to the specified `port` and `host`. If the second parameter is omitted, localhost is assumed. -When the connection is established the `"connect"` event will be emitted. +When the stream is established the `"connect"` event will be emitted. -### connection.connect(port, host="127.0.0.1") +### stream.connect(port, host="127.0.0.1") -Opens a connection to the specified `port` and `host`. `createConnection()` -also opens a connection; normally this method is not needed. Use this only if -a connection is closed and you want to reuse the object to connect to another +Opens a stream to the specified `port` and `host`. `createConnection()` +also opens a stream; normally this method is not needed. Use this only if +a stream is closed and you want to reuse the object to connect to another server. This function is asynchronous. When the `"connect"` event is emitted the -connection is established. If there is a problem connecting, the `"connect"` +stream is established. If there is a problem connecting, the `"connect"` event will not be emitted, the `"close"` event will be emitted with `had_error == true`. -### connection.remoteAddress +### stream.remoteAddress The string representation of the remote IP address. For example, `"74.125.127.100"` or `"2001:4860:a005::68"`. This member is only present in server-side connections. -### connection.readyState +### stream.readyState Either `"closed"`, `"open"`, `"opening"`, `"readOnly"`, or `"writeOnly"`. -### connection.setEncoding(encoding) +### stream.setEncoding(encoding) Sets the encoding (either `"ascii"`, `"utf8"`, or `"binary"`) for data that is received. -### connection.write(data, encoding="ascii") +### stream.write(data, encoding="ascii") -Sends data on the connection. The second parameter specifies the encoding in +Sends data on the stream. The second parameter specifies the encoding in the case of a string--it defaults to ASCII because encoding to UTF8 is rather slow. @@ -1636,61 +1737,40 @@ Returns `true` if the entire data was flushed successfully to the kernel buffer. Returns `false` if all or part of the data was queued in user memory. `'drain'` will be emitted when the buffer is again free. -### connection.close() +### stream.end() -Half-closes the connection. I.E., it sends a FIN packet. It is possible the +Half-closes the stream. I.E., it sends a FIN packet. It is possible the server will still send some data. After calling this `readyState` will be `"readOnly"`. -### connection.forceClose() +### stream.destroy() -Ensures that no more I/O activity happens on this socket. Only necessary in +Ensures that no more I/O activity happens on this stream. Only necessary in case of errors (parse error or so). -### connection.pause() +### stream.pause() Pauses the reading of data. That is, `"data"` events will not be emitted. Useful to throttle back an upload. -### connection.resume() +### stream.resume() Resumes reading after a call to `pause()`. -### connection.setTimeout(timeout) +### stream.setTimeout(timeout) -Sets the connection to timeout after `timeout` milliseconds of inactivity on -the connection. By default all `tcp.Connection` objects have a timeout of 60 +Sets the stream to timeout after `timeout` milliseconds of inactivity on +the stream. By default all `net.Stream` objects have a timeout of 60 seconds (60000 ms). If `timeout` is 0, then the idle timeout is disabled. -### connection.setNoDelay(noDelay=true) +### stream.setNoDelay(noDelay=true) Disables the Nagle algorithm. By default TCP connections use the Nagle algorithm, they buffer data before sending it off. Setting `noDelay` will -immediately fire off data each time `connection.write()` is called. +immediately fire off data each time `stream.write()` is called. -### connection.verifyPeer() - -Returns an integer indicating the trusted status of the peer in a TLS -connection. - -Returns 1 if the peer's certificate is issued by one of the trusted CAs, the -certificate has not been revoked, is in the issued date range, and if the peer -is the server, matches the hostname. - -Returns 0 if no certificate was presented by the peer, or negative result if -the verification fails (with a given reason code). This function is -synchronous. - -### connection.getPeerCertificate(format) - -For a TLS connection, returns the peer's certificate information, as defined -by the given format. - -A format of "DNstring" gives a single string with the combined Distinguished -Name (DN) from the certificate, as comma delimited name=value pairs as defined -in RFC2253. This function is synchronous. ## DNS module @@ -1702,16 +1782,14 @@ resolves the IP addresses which are returned. var dns = require("dns"), sys = require("sys"); - dns.resolve4("www.google.com", function (err, addresses, ttl, cname) { + dns.resolve4("www.google.com", function (err, addresses) { if (err) throw err; sys.puts("addresses: " + JSON.stringify(addresses)); - sys.puts("ttl: " + JSON.stringify(ttl)); - sys.puts("cname: " + JSON.stringify(cname)); for (var i = 0; i < addresses.length; i++) { var a = addresses[i]; - dns.reverse(a, function (err, domains, ttl, cname) { + dns.reverse(a, function (err, domains) { if (err) { puts("reverse for " + a + " failed: " + e.message); } else { @@ -1728,9 +1806,7 @@ specified by rrtype. Valid rrtypes are `A` (IPV4 addresses), `AAAA` (IPV6 addresses), `MX` (mail exchange records), `TXT` (text records), `SRV` (SRV records), and `PTR` (used for reverse IP lookups). -The callback has arguments `(err, addresses, ttl, cname)`. `ttl` -(time-to-live) is an integer specifying the number of seconds this result is -valid for. `cname` is the canonical name for the query. The type of each item +The callback has arguments `(err, addresses)`. The type of each item in `addresses` is determined by the record type, and described in the documentation for the corresponding lookup methods below. @@ -1772,7 +1848,7 @@ of SRV records are priority, weight, port, and name (e.g., `[{"priority": 10, {" Reverse resolves an ip address to an array of domain names. -The callback has arguments `(err, domains, ttl, cname)`. `ttl` (time-to-live) is an integer specifying the number of seconds this result is valid for. `cname` is the canonical name for the query. `domains` is an array of domains. +The callback has arguments `(err, domains)`. If there an an error, `err` will be non-null and an instanceof the Error object. @@ -2023,10 +2099,10 @@ result of the last expression. The library is called `/repl.js` and it can be used like this: var sys = require("sys"), - tcp = require("tcp"), + net = require("net"), repl = require("repl"); nconnections = 0; - tcp.createServer(function (c) { + net.createServer(function (c) { sys.error("Connection!"); nconnections += 1; c.close(); diff --git a/doc/index.html b/doc/index.html index 7c5f81fef19..e49f55ae2a9 100644 --- a/doc/index.html +++ b/doc/index.html @@ -42,12 +42,12 @@

-var sys = require('sys'), 
+var sys = require('sys'),
    http = require('http');
 http.createServer(function (req, res) {
   setTimeout(function () {
     res.writeHead(200, {'Content-Type': 'text/plain'});
-    res.close('Hello World');
+    res.end('Hello World\n');
   }, 2000);
 }).listen(8000);
 sys.puts('Server running at http://127.0.0.1:8000/');
@@ -79,7 +79,7 @@ var server = tcp.createServer(function (socket) { }); socket.addListener("end", function () { socket.write("goodbye\r\n"); - socket.close(); + socket.end(); }); }); server.listen(7000, "localhost");
From b8bb6e90074452b41c45a31b03d261484cb841d4 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 15:20:13 -0700 Subject: [PATCH 47/73] Close child process stdin on SIGCHLD --- lib/child_process.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/child_process.js b/lib/child_process.js index db452110d85..b0f8316858a 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -56,6 +56,7 @@ function ChildProcess () { internal.onexit = function (code) { gotCHLD = true; exitCode = code; + stdin.close(); if (!stdout.readable && !stderr.readable) { self.emit('exit', exitCode); } From 08a09bb50abcc355941f62deecece5cb6f3a2382 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 16:31:02 -0700 Subject: [PATCH 48/73] Use some more Binary/F methods for Buffer --- doc/api.markdown | 31 +++++++------------------- lib/buffer.js | 45 ++++++++++++++++++++++++++++++-------- lib/http.js | 21 ++++-------------- lib/net.js | 34 ++++++---------------------- test/simple/test-buffer.js | 6 ++--- 5 files changed, 58 insertions(+), 79 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index 3fc5028b6a2..d935c07e85b 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -31,10 +31,10 @@ All of the examples in the documentation can be run similarly. Pure Javascript is Unicode friendly but not nice to pure binary data. When dealing with TCP streams or the file system, it's necessary to handle octet -streams. Node has several stratagies for manipulating, creating, and +streams. Node has several strategies for manipulating, creating, and consuming octet streams. -Raw data is stored in instaces of the `Buffer` class. A `Buffer` is similar +Raw data is stored in instances of the `Buffer` class. A `Buffer` is similar to an array of integers but correspond to a raw memory allocation outside the V8 heap. A `Buffer` cannot be resized. Access the class at `require('buffer').Buffer`. @@ -59,29 +59,14 @@ Binary (`"binary"`). `"ascii"` and `"binary"` only look at the first 8 bits of the 16bit JavaScript string characters. The following `Buffer` methods allow decoding and encoding of strings: -- **`buffer.utf8Write(string, offset)`**: Writes `string` to the buffer at -`offset` using UTF-8 encoding. Returns the number of octets written. If +- **`buffer.write(string, encoding, offset)`**: Writes `string` to the buffer at +`offset` using the given encoding. Returns number of octets written. If `buffer` did not contain enough space to fit the entire string it will write -a partial amount of the string. However, this method will not write partial -characters. +a partial amount of the string. In the case of `encoding=='utf8'`, the +method will not write partial characters. -- **`buffer.binaryWrite(string, offset)`**: Writes `string` to the buffer at -`offset` using binary encoding - that is it will only use the first 8 bits -of each character. Write a partial string if not enough space remains. -Returns number of octets written. - -- **`buffer.asciiWrite(string, offset)`**: Writes `string` to the buffer at -`offset` using ASCII encoding. Faster than `utf8Write()`. Write a partial -string if not enough space remains. Returns number of octets written. - -- **`buffer.utf8Slice(start, end)`**: Decodes and returns a string assuming -UTF-8 encoding beginning at `start` and ending at `end`. - -- **`buffer.binarySlice(start, end)`**: Decodes and returns a string assuming -binary encoding beginning at `start` and ending at `end`. - -- **`buffer.asciiSlice(start, end)`**: Decodes and returns a string assuming -ASCII encoding beginning at `start` and ending at `end`. +- **`buffer.toString(encoding, start, end)`**: Decodes and returns a string assuming +in the given encoding beginning at `start` and ending at `end`. diff --git a/lib/buffer.js b/lib/buffer.js index 4f7699e6387..66401b4460b 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -18,19 +18,46 @@ Buffer.prototype.inspect = function () { }; Buffer.prototype.toString = function (encoding, start, stop) { - encoding = encoding || 'utf8'; + encoding = (encoding || 'utf8').toLowerCase(); if (!start) start = 0; if (!stop) stop = this.length; - if (encoding == 'utf8') { - return this.utf8Slice(start, stop); - } else if (encoding == 'ascii') { - return this.asciiSlice(start, stop); - } else if (encoding == 'binary') { - return this.binarySlice(start, stop); - } else { - throw new Error('Unknown encoding'); + switch (encoding) { + case 'utf8': + case 'utf-8': + return this.utf8Slice(start, stop); + + case 'ascii': + return this.asciiSlice(start, stop); + + case 'binary': + return this.binarySlice(start, stop); + + default: + throw new Error('Unknown encoding'); + } +}; + +Buffer.prototype.write = function (string, encoding, offset) { + encoding = (encoding || 'utf8').toLowerCase(); + switch (encoding) { + case 'utf8': + case 'utf-8': + return this.utf8Write(string, offset); + + case 'ascii': + return this.asciiWrite(string, offset); + + case 'binary': + return this.binaryWrite(string, offset); + + default: + throw new Error('Unknown encoding'); } }; + + + + diff --git a/lib/http.js b/lib/http.js index d0ae3064c59..da6cb384d91 100644 --- a/lib/http.js +++ b/lib/http.js @@ -31,7 +31,7 @@ function newParser (type) { // Only servers will get URL events. parser.onURL = function (b, start, len) { - var slice = b.asciiSlice(start, start+len); + var slice = b.toString('ascii', start, start+len); if (parser.incoming.url) { parser.incoming.url += slice; } else { @@ -41,7 +41,7 @@ function newParser (type) { }; parser.onHeaderField = function (b, start, len) { - var slice = b.asciiSlice(start, start+len).toLowerCase(); + var slice = b.toString('ascii', start, start+len).toLowerCase(); if (parser.value) { parser.incoming._addHeaderLine(parser.field, parser.value); parser.field = null; @@ -55,7 +55,7 @@ function newParser (type) { }; parser.onHeaderValue = function (b, start, len) { - var slice = b.asciiSlice(start, start+len); + var slice = b.toString('ascii', start, start+len); if (parser.value) { parser.value += slice; } else { @@ -88,20 +88,7 @@ function newParser (type) { if (!enc) { parser.incoming.emit('data', b.slice(start, start+len)); } else { - var string; - switch (enc) { - case 'utf8': - string = b.utf8Slice(start, start+len); - break; - case 'ascii': - string = b.asciiSlice(start, start+len); - break; - case 'binary': - string = b.binarySlice(start, start+len); - break; - default: - throw new Error('Unsupported encoding ' + enc + '. Use Buffer'); - } + var string = b.toString(enc, start, start+len); parser.incoming.emit('data', string); } }; diff --git a/lib/net.js b/lib/net.js index ff616eb9643..e99f1162bff 100644 --- a/lib/net.js +++ b/lib/net.js @@ -308,22 +308,7 @@ function initStream (self) { // Optimization: emit the original buffer with end points if (self.ondata) self.ondata(pool, start, end); } else { - // TODO remove me - we should only output Buffer - - var string; - switch (self._encoding) { - case 'utf8': - string = pool.utf8Slice(start, end); - break; - case 'ascii': - string = pool.asciiSlice(start, end); - break; - case 'binary': - string = pool.binarySlice(start, end); - break; - default: - throw new Error('Unsupported encoding ' + self._encoding + '. Use Buffer'); - } + var string = pool.toString(self._encoding, start, end); self.emit('data', string); } } @@ -442,21 +427,16 @@ Stream.prototype._writeOut = function (data, encoding) { allocNewPool(); } - if (encoding == 'binary') { - bytesWritten = pool.binaryWrite(data, pool.used); - charsWritten = bytesWritten; - } else if (encoding == 'ascii') { - bytesWritten = pool.asciiWrite(data, pool.used); - charsWritten = bytesWritten; - - } else { + if (encoding == 'utf8' || encoding == 'utf-8') { // default to utf8 - bytesWritten = pool.utf8Write(data, pool.used); + bytesWritten = pool.write(data, 'utf8', pool.used); // XXX Hacky way to find out the number of characters written. // Waiting for a more optimal way: http://codereview.chromium.org/1539013 - var _s = pool.utf8Slice(pool.used, pool.used + bytesWritten); + var _s = pool.toString('utf8', pool.used, pool.used + bytesWritten); charsWritten = _s.length; - + } else { + bytesWritten = pool.write(data, encoding, pool.used); + charsWritten = bytesWritten; } assert(bytesWritten > 0); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 88282c5b0a0..084c268ad61 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -34,12 +34,12 @@ for (var j = 0; j < 500; j++) { for (var i = 0; i < asciiString.length; i++) { b[i] = asciiString.charCodeAt(i); } - var asciiSlice = b.asciiSlice(0, asciiString.length); + var asciiSlice = b.toString('ascii', 0, asciiString.length); assert.equal(asciiString, asciiSlice); var written = b.asciiWrite(asciiString, offset); assert.equal(asciiString.length, written); - var asciiSlice = b.asciiSlice(offset, offset+asciiString.length); + var asciiSlice = b.toString('ascii', offset, offset+asciiString.length); assert.equal(asciiString, asciiSlice); var sliceA = b.slice(offset, offset+asciiString.length); @@ -91,7 +91,7 @@ var testValue = '\u00F6\u65E5\u672C\u8A9E'; // ö日本語 var buffer = new Buffer(32); var size = buffer.utf8Write(testValue, 0); puts('bytes written to buffer: ' + size); -var slice = buffer.utf8Slice(0, size); +var slice = buffer.toString('utf8', 0, size); assert.equal(slice, testValue); From 631e5bf5cb3d31f9245d9814e1de1d84c0d83395 Mon Sep 17 00:00:00 2001 From: Matt Ranney Date: Tue, 30 Mar 2010 23:12:15 -0700 Subject: [PATCH 49/73] Improve child_process documentation. --- doc/api.markdown | 173 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 29 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index d935c07e85b..fd12bcab62c 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -764,6 +764,7 @@ Stops a interval from triggering. sys.puts("Started timer."); + ## Child Processes Node provides a tri-directional `popen(3)` facility through the `ChildProcess` @@ -781,56 +782,170 @@ Child processes always have three streams associated with them. `child.stdin`, - **`exit`** - `callback(code)`: This event is emitted after the child process ends. `code` is the final - exit code of the process. One can be assured that after this event is - emitted that the `"output"` and `"error"` callbacks will no longer be made. + exit code of the process. After this event is emitted, the `"output"` + and `"error"` callbacks will no longer be made. -### require("child_process").spawn(command, args=[], env=process.env) + +### child_process.spawn(command, args, env) Launches a new process with the given `command`, command line arguments, and -environmental variables. For example: +environment variables. If omitted, `args` defaults to an empty Array, and `env` +defaults to `process.env`. - // Pipe a child process output to - // parent process output - var ls = spawn("ls", ["-lh", "/usr"]); - ls.stdout.addListener('data', function (data) { - process.stdout.write(data); +Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the exit code: + + var sys = require("sys"), + spawn = require("child_process").spawn, + ls = spawn("ls", ["-lh", "/usr"]); + + ls.stdout.addListener("data", function (data) { + sys.print("stdout: " + data); }); + ls.stderr.addListener("data", function (data) { + sys.print("stderr: " + data); + }); + + ls.addListener("exit", function (code) { + sys.puts("child process exited with code " + code); + }); + + +Example of checking for failed exec: + + var sys = require("sys"), + spawn = require("child_process").spawn, + child = spawn("bad_command"); + + child.stderr.addListener("data", function (data) { + if (/^execvp\(\)/.test(data.asciiSlice(0,data.length))) { + sys.puts("Failed to start child process."); + } + }); + + +See also: `child_process.exec()` + + +### child.kill(signal) + +Send a signal to the child process. If no argument is given, the process will +be sent `"SIGTERM"`. See `signal(7)` for a list of available signals. + + var sys = require("sys"), + spawn = require("child_process").spawn, + grep = spawn("grep", ["ssh"]); + + grep.addListener("exit", function (code) { + sys.puts("child process exited with code " + code); + }); + + // send SIGHUP to process + grep.kill("SIGHUP"); + +Note that while the function is called `kill`, the signal delivered to the child +process may not actually kill it. `kill` really just sends a signal to a process. + +See `kill(2)` + + ### child.pid The PID of the child process. -### child.write(data, encoding="ascii") +Example: + + var sys = require("sys"), + spawn = require("child_process").spawn, + grep = spawn("grep", ["ssh"]); + + sys.puts("Spawned child pid: " + grep.pid); + grep.stdin.close(); + + +### child.stdin.write(data, encoding) Write data to the child process's `stdin`. The second argument is optional and specifies the encoding: possible values are `"utf8"`, `"ascii"`, and `"binary"`. -### child.close() +Example: A very elaborate way to run "ps ax | grep ssh" -Closes the process's `stdin` stream. + var sys = require("sys"), + spawn = require("child_process").spawn, + ps = spawn("ps", ["ax"]), + grep = spawn("grep", ["ssh"]); -### child.kill(signal="SIGTERM") - -Send a signal to the child process. If no argument is given, the process will -be sent `"SIGTERM"`. See signal(7) for a list of available signals. - - -### require("child_process").exec(command, callback) - -High-level way to executes a command as a child process and buffer the -output and return it in a callback. - - var exec = require("child_process").exec; - exec("ls /", function (err, stdout, stderr) { - if (err) throw err; - sys.puts(stdout); + ps.stdout.addListener("data", function (data) { + grep.stdin.write(data); }); -The callback gets the arguments `(err, stdout, stderr)`. On success +err+ -will be `null`. On error `err` will be an instance of `Error` and `err.code` + ps.stderr.addListener("data", function (data) { + sys.print("ps stderr: " + data); + }); + + ps.addListener("exit", function (code) { + if (code !== 0) { + sys.puts("ps process exited with code " + code); + } + grep.stdin.close(); + }); + + grep.stdout.addListener("data", function (data) { + sys.print(data); + }); + + grep.stderr.addListener("data", function (data) { + sys.print("grep stderr: " + data); + }); + + grep.addListener("exit", function (code) { + if (code !== 0) { + sys.puts("grep process exited with code " + code); + } + }); + + +### child.stdin.close() + +Closes the child process's `stdin` stream. This often causes the child process to terminate. + +Example: + + var sys = require("sys"), + spawn = require("child_process").spawn, + grep = spawn("grep", ["ssh"]); + + grep.addListener("exit", function (code) { + sys.puts("child process exited with code " + code); + }); + + grep.stdin.close(); + + +### child_process.exec(command, callback) + +High-level way to execute a command as a child process, buffer the +output, and return it all in a callback. + + var sys = require("sys"), + exec = require("child_process").exec, + child; + + child = exec("cat *.js bad_file | wc -l", function (error, stdout, stderr) { + sys.print("stdout: " + stdout); + sys.print("stderr: " + stderr); + if (error !== null) { + sys.puts("exec error: " + error); + } + }); + +The callback gets the arguments `(error, stdout, stderr)`. On success, `error` +will be `null`. On error, `error` will be an instance of `Error` and `err.code` will be the exit code of the child process. + + ## File System File I/O is provided by simple wrappers around standard POSIX functions. To From 323a5e11e5ae53a081210da12dd43beb595839c6 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 17:39:33 -0700 Subject: [PATCH 50/73] Change how events are represented in docs --- doc/api.markdown | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index fd12bcab62c..a87f0c9c7f8 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -10,9 +10,7 @@ World": http = require("http"); http.createServer(function (request, response) { - response.writeHead(200, { - "Content-Type": "text/plain" - }); + response.writeHead(200, {"Content-Type": "text/plain"}); response.end("Hello World\n"); }).listen(8000); @@ -136,19 +134,19 @@ are readable, writable, or both. All streams are instances of `EventEmitter`. A **readable stream** has the following methods, members, and events. -- **`stream.addListener('data', function (data) { ... })`**: +- Event: **`'data'`** - `callback(data)`: The `'data'` event emits either a `Buffer` (by default) or a string if `setEncoding()` was used. -- **`stream.addListener('end', function () { ... })`**: +- Event: **`'end'`** - `callback()`: Emitted when the stream has received an EOF (FIN in TCP terminology). Indicates that no more `'data'` events will happen. If the stream is also writable, it may be possible to continue writing. -- **`stream.addListener('error', function (exception) { ... })`**: +- Event: **`'error'`** - `callback(exception)`: Emitted if there was an error receiving data. -- **`stream.addListener('close', function () { ... })`**: +- Event: **`'close'`** - `callback()`: Emitted when the underlying file descriptor has be closed. Not all streams will emit this. (For example, an incoming HTTP request will not emit `'close'`.) @@ -170,14 +168,14 @@ Closes the underlying file descriptor. Stream will not emit any more events. A **writable stream** has the following methods, members, and events. -- **`stream.addListener('drain', function () { ... })`**: +- Event: **`'drain'`** - `callback()`: Emitted after a `write()` method was called that returned `false` to indicate that it is safe to write again. -- **`stream.addListener('error', function (e) { ... })`**: +- Event: **`'error'`** - `callback(exception)`: Emitted on error with the exception `e`. -- **`stream.addListener('close', function () { ... })`**: +- Event **`'close'`** - `callback()`: Emitted when the underlying file descriptor has been closed. - **`stream.write(string, encoding)`**: @@ -233,7 +231,7 @@ The `process` object is a global object and can be accessed from anywhere. It is an instance of `EventEmitter` and has the following events: -### process.addListener('exit', function () { ... }) +### Event: 'exit' - callback() Emitted when the process is about to exit. This is a good hook to perform constant time checks of the module's state (like for unit tests). The main @@ -251,7 +249,7 @@ Example of listening for `exit`: sys.puts("About to exit."); }); -### process.addListener('uncaughtException', function (err) { ... }) +### Event: 'uncaughtException' - callback(err) Emitted when an exception bubbles all the way back to the event loop. If a listener is added for this exception, the default action (which is to print @@ -279,7 +277,7 @@ your program's flow. Especially for server programs that are designed to stay running forever, `uncaughtException` can be a useful safety mechanism. -### process.addListener('SIGINT', function () { ... }) +### Event: 'SIGINT' - callback() Emitted when the processes receives a signal. See sigaction(2) for a list of standard POSIX signal names such as SIGINT, SIGUSR1, etc. From a5184fe938d2fd3de2018d97c601e7ce9b9eaafe Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 8 Apr 2010 22:42:02 -0700 Subject: [PATCH 51/73] Change api.html style --- doc/api_header.html | 111 ++++++++++++++++++++++++++++++++++++++------ doc/sh_vim-dark.css | 2 +- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/doc/api_header.html b/doc/api_header.html index 43dbaeb679f..f9eafdc99f7 100644 --- a/doc/api_header.html +++ b/doc/api_header.html @@ -1,20 +1,103 @@ - - - - - -NODE(1) - - - - - - - + + + + + node(1) -- evented I/O for V8 JavaScript + + + + + +
Table of Contents
+
+ +

node(1)

+ +
    +
  1. node(1)
  2. +
  3. +
  4. node(1)
  5. +
diff --git a/doc/sh_vim-dark.css b/doc/sh_vim-dark.css index 6b7a1c95f53..3b6b3992f55 100644 --- a/doc/sh_vim-dark.css +++ b/doc/sh_vim-dark.css @@ -5,7 +5,7 @@ } .sh_sourceCode .sh_symbol , .sh_sourceCode .sh_cbracket { - color: #cd5; + color: #fff; } .sh_sourceCode .sh_keyword { From 06b9c8bf1f75c20433413a6aececa26326641a3f Mon Sep 17 00:00:00 2001 From: Herbert Vojcik Date: Fri, 9 Apr 2010 14:22:00 +0200 Subject: [PATCH 52/73] Fix of normalizing paths of form ./../the/rest --- src/node.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node.js b/src/node.js index e0fad180d84..675e3bc048f 100644 --- a/src/node.js +++ b/src/node.js @@ -351,6 +351,7 @@ var pathModule = createInternalModule("path", function (exports) { directory === ".." && directories.length && prev !== ".." + && prev !== "." && prev !== undefined && (prev !== "" || keepBlanks) ) { From ff56d6364eb09079b1ab6e9ef32d66c2cb4c0bfd Mon Sep 17 00:00:00 2001 From: Tim Caswell Date: Fri, 9 Apr 2010 11:56:22 -0500 Subject: [PATCH 53/73] Fix child_process to use end() instead of close() in the stdin stream. --- lib/child_process.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/child_process.js b/lib/child_process.js index b0f8316858a..4ed5a544a00 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -56,7 +56,7 @@ function ChildProcess () { internal.onexit = function (code) { gotCHLD = true; exitCode = code; - stdin.close(); + stdin.end(); if (!stdout.readable && !stderr.readable) { self.emit('exit', exitCode); } From b36f11d7b50e12838b414b866878748109c056ec Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 10:42:20 -0700 Subject: [PATCH 54/73] Set old/new from benchmark script args --- benchmark/http_simple.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 28c215aaf5e..e1eb6b57799 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -1,7 +1,8 @@ path = require("path"); var puts = require("sys").puts; -var old = false; + +var old = (process.argv[2] == 'old'); http = require(old ? "http_old" : 'http'); if (old) puts('old version'); From 9331218449921290d699fc8eaaa77a9b7155223b Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 10:44:08 -0700 Subject: [PATCH 55/73] Servers shouldn't die on EMFILE --- lib/net.js | 39 ++++++++++++++++++++++++++++++++++++--- src/node_net2.cc | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/net.js b/lib/net.js index e99f1162bff..07e34d3fce9 100644 --- a/lib/net.js +++ b/lib/net.js @@ -42,6 +42,7 @@ var getsockname = binding.getsockname; var errnoException = binding.errnoException; var EINPROGRESS = binding.EINPROGRESS; var ENOENT = binding.ENOENT; +var EMFILE = binding.EMFILE; var END_OF_FILE = 42; @@ -238,6 +239,29 @@ var ioWatchers = new FreeList("iowatcher", 100, function () { }); +// waitingForFDs stores servers which have experienced EMFILE. +// When a file descriptor becomes available through closeFD() +// a server from waitingForFDs is started. + +var waitingForFDs = []; + +function closeFD(fd) { + close(fd); + + // Try to recover from EMFILE + + var server, serverFD; + while (server = waitingForFDs.shift()) { + serverFD = parseInt(server.fd); + if (serverFD && serverFD > 0) { + server.watcher.set(serverFD, true, false); + server.watcher.start(); + return; + } + } +} + + // Allocated on demand. var pool = null; function allocNewPool () { @@ -675,7 +699,7 @@ Stream.prototype.destroy = function (exception) { // FIXME Bug when this.fd == 0 if (typeof this.fd == 'number') { - close(this.fd); + closeFD(this.fd); this.fd = null; process.nextTick(function () { if (exception) self.emit('error', exception); @@ -733,7 +757,16 @@ function Server (listener) { self.watcher.host = self; self.watcher.callback = function () { while (self.fd) { - var peerInfo = accept(self.fd); + try { + var peerInfo = accept(self.fd); + } catch (e) { + if (e.errno == EMFILE) { + waitingForFDs.push(self); + self.watcher.stop(); + return; + } + throw e; + } if (!peerInfo) return; var s = new Stream(peerInfo.fd); @@ -846,7 +879,7 @@ Server.prototype.close = function () { self.watcher.stop(); - close(self.fd); + closeFD(self.fd); self.fd = null; if (self.type === "unix") { diff --git a/src/node_net2.cc b/src/node_net2.cc index 2ba0f3f1ac1..eb6ea1aa78b 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -1294,6 +1294,7 @@ void InitNet2(Handle target) { NODE_SET_METHOD(target, "errnoException", CreateErrnoException); target->Set(String::NewSymbol("ENOENT"), Integer::New(ENOENT)); + target->Set(String::NewSymbol("EMFILE"), Integer::New(EMFILE)); target->Set(String::NewSymbol("EINPROGRESS"), Integer::New(EINPROGRESS)); target->Set(String::NewSymbol("EINTR"), Integer::New(EINTR)); target->Set(String::NewSymbol("EACCES"), Integer::New(EACCES)); From fd0bebcdbc1509af16229108a2e05c512a8c99ce Mon Sep 17 00:00:00 2001 From: Micheil Smith Date: Sat, 10 Apr 2010 05:34:21 +1000 Subject: [PATCH 56/73] Mods to the docs --- doc/api_header.html | 2 +- doc/doc.js | 68 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/doc/api_header.html b/doc/api_header.html index f9eafdc99f7..a133fd3aead 100644 --- a/doc/api_header.html +++ b/doc/api_header.html @@ -11,7 +11,7 @@ } #man, #man code, #man pre, #man tt, #man kbd, #man samp { font-family:consolas,monospace; - font-size:16px; + font-size:14px; line-height:1.3; color:#eee; background:#22252a; } diff --git a/doc/doc.js b/doc/doc.js index aeb1669e35e..3f092e4c238 100644 --- a/doc/doc.js +++ b/doc/doc.js @@ -1,15 +1,63 @@ $(function() { - var $toc = $('#toc'); - $('h2').each(function() { - var - $h2 = $(this), - $div = $('
'), - $a = $('') - .text($h2.text()) - .attr('href', '#'+$h2.attr('id')); + var count = 0; + var cur_level, last_level = 0, html = ""; + $(":header").filter("h2, h3").each(function(i, el){ + $(this).attr("id", $(this).text().replace(/\(.*\)$/gi, "").replace(/[\s\.]+/gi, "-").toLowerCase()+"-"+(count++)) + + cur_level = el.tagName.substr(1,1); + + if(cur_level > last_level){ + html += "
    "; + } else if (cur_level < last_level){ + html += "
" + } + if(i > 0){ + html += ""; + } + html += '
  • '; + html += ''+$(el).text().replace(/\(.*\)$/gi, "")+""; - $toc.append($div.append($a)); + last_level = cur_level; }); - + + html += ""; + + $("#toc").append(html); + + $("#toc ul li").addClass("topLevel"); + + $("#toc ul li ul").each(function(i, el){ + $(el).parent().removeClass("topLevel").prepend('+'); + }) + + $("#toc ul li ul").hide(); + $("#toc ul li .toggler").bind("click", function(e){ + var el = $("ul", $(this).parent()); + if(el.css("display") == "none"){ + el.slideDown(); + $(this).text("–"); + } else { + el.slideUp(); + $(this).text("+"); + } + e.preventDefault(); + return false; + }); + + $('a[href*=#]').click(function() { + if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') + && location.hostname == this.hostname) { + var $target = $(this.hash); + $target = $target.length && $target + || $('[name=' + this.hash.slice(1) +']'); + if ($target.length) { + var targetOffset = $target.offset().top; + $('html,body') + .animate({scrollTop: targetOffset}, 500); + return false; + } + } + }); + sh_highlightDocument(); }); \ No newline at end of file From 03ea4b644e98c59d41af4ee14fb01a2fbc69f867 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 14:51:20 -0700 Subject: [PATCH 57/73] Improve(\?) docs --- doc/api.markdown | 1112 +++++++++++++++++++++++-------------------- doc/api_header.html | 136 ++++-- 2 files changed, 690 insertions(+), 558 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index a87f0c9c7f8..3038d16c2a9 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -3,18 +3,18 @@ node(1) -- evented I/O for V8 JavaScript ## Synopsis -An example of a web server written with Node which responds with "Hello -World": +An example of a web server written with Node which responds with 'Hello +World': - var sys = require("sys"), - http = require("http"); + var sys = require('sys'), + http = require('http'); http.createServer(function (request, response) { - response.writeHead(200, {"Content-Type": "text/plain"}); - response.end("Hello World\n"); + response.writeHead(200, {'Content-Type': 'text/plain'}); + response.end('Hello World\n'); }).listen(8000); - sys.puts("Server running at http://127.0.0.1:8000/"); + sys.puts('Server running at http://127.0.0.1:8000/'); To run the server, put the code into a file called `example.js` and execute it with the node program @@ -25,6 +25,72 @@ it with the node program All of the examples in the documentation can be run similarly. +## Modules + +Node uses the CommonJS module system. + +Node has a simple module loading system. In Node, files and modules are in +one-to-one correspondence. As an example, `foo.js` loads the module +`circle.js` in the same directory. + +The contents of `foo.js`: + + var circle = require('./circle'), + var sys = require('sys'); + sys.puts( 'The area of a circle of radius 4 is ' + + circle.area(4)); + +The contents of `circle.js`: + + var PI = 3.14; + + exports.area = function (r) { + return PI * r * r; + }; + + exports.circumference = function (r) { + return 2 * PI * r; + }; + +The module `circle.js` has exported the functions `area()` and +`circumference()`. To export an object, add to the special `exports` +object. (Alternatively, one can use `this` instead of `exports`.) Variables +local to the module will be private. In this example the variable `PI` is +private to `circle.js`. The function `puts()` comes from the module `'sys'`, +which is a built-in module. Modules which are not prefixed by `'./'` are +built-in module--more about this later. + +A module prefixed with `'./'` is relative to the file calling `require()`. +That is, `circle.js` must be in the same directory as `foo.js` for +`require('./circle')` to find it. + +Without the leading `'./'`, like `require('assert')` the module is searched +for in the `require.paths` array. `require.paths` on my system looks like +this: + +`[ '/home/ryan/.node_libraries' ]` + +That is, when `require('assert')` is called Node looks for: + + * 1: `/home/ryan/.node_libraries/assert.js` + * 2: `/home/ryan/.node_libraries/assert.node` + * 3: `/home/ryan/.node_libraries/assert/index.js` + * 4: `/home/ryan/.node_libraries/assert/index.node` + +interrupting once a file is found. Files ending in `'.node'` are binary Addon +Modules; see the section below about addons. `'index.js'` allows one to +package a module as a directory. + +`require.paths` can be modified at runtime by simply unshifting new +paths onto it, or at startup with the `NODE_PATH` environmental +variable (which should be a list of paths, colon separated). + +Use `process.mixin()` to include modules into the global namespace. + + process.mixin(GLOBAL, require('./circle'), require('sys')); + puts('The area of a circle of radius 4 is ' + area(4)); + + ## String Encodings and Buffers Pure Javascript is Unicode friendly but not nice to pure binary data. When @@ -37,58 +103,61 @@ to an array of integers but correspond to a raw memory allocation outside the V8 heap. A `Buffer` cannot be resized. Access the class at `require('buffer').Buffer`. -- **`new Buffer(size)`**: Allocates a new buffer of `size` octets. +Node supports 3 string encodings. UTF-8 (`'utf8'`), ASCII (`'ascii'`), and +Binary (`'binary'`). `'ascii'` and `'binary'` only look at the first 8 bits +of the 16bit JavaScript string characters. -- **`buffer[index]`**: Get and set the octet at `index`. The value can be -between 0x00 and 0xFF. +### new Buffer(size) +Allocates a new buffer of `size` octets. -- **`buffer.length`**: length in octets. +### buffer[index] +Get and set the octet at `index`. The value can be between `0x00` and `0xFF`. -- **`buffer.copy(targetBuffer, targetStart, start, end)`**: +### buffer.length +length in octets. + +### buffer.copy(targetBuffer, targetStart, start, end) Does a memcpy() between buffers. -- **`buffer.slice(start, end)`**: Returns a new buffer which references the +### buffer.slice(start, end) +Returns a new buffer which references the same memory as the old, but offset and cropped by the `start` and `end` indexes. **Modifying the new buffer slice will modify memory in the original buffer!** -Node supports 3 string encodings. UTF-8 (`"utf8"`), ASCII (`"ascii"`), and -Binary (`"binary"`). `"ascii"` and `"binary"` only look at the first 8 bits -of the 16bit JavaScript string characters. The following `Buffer` methods -allow decoding and encoding of strings: +### buffer.write(string, encoding, offset) +Writes `string` to the buffer at `offset` using the given encoding. Returns +number of octets written. If `buffer` did not contain enough space to fit +the entire string it will write a partial amount of the string. In the case +of `encoding=='utf8'`, the method will not write partial characters. -- **`buffer.write(string, encoding, offset)`**: Writes `string` to the buffer at -`offset` using the given encoding. Returns number of octets written. If -`buffer` did not contain enough space to fit the entire string it will write -a partial amount of the string. In the case of `encoding=='utf8'`, the -method will not write partial characters. - -- **`buffer.toString(encoding, start, end)`**: Decodes and returns a string assuming -in the given encoding beginning at `start` and ending at `end`. +### buffer.toString(encoding, start, end) +Decodes and returns a string assuming in the given encoding beginning at +`start` and ending at `end`. -## Events +## EventEmitter Many objects in Node emit events: a TCP server emits an event each time there is a stream, a child process emits an event when it exits. All objects which emit events are instances of `events.EventEmitter`. Events are represented by a camel-cased string. Here are some examples: -`"stream"`, `"data"`, `"messageBegin"`. +`'stream'`, `'data'`, `'messageBegin'`. Functions can be then be attached to objects, to be executed when an event is emitted. These functions are called _listeners_. +`require('events').EventEmitter` to access the `EventEmitter` class. -### events.EventEmitter - -`require("events")` to access the events module. - -All EventEmitters emit the event `"newListener"` when new listeners are +All EventEmitters emit the event `'newListener'` when new listeners are added. -- **`"newListener"`** - `callback(event, listener)`: +### Event: 'newListener' + +`function (event, listener) { }` + This event is made any time someone adds a new listener. @@ -97,7 +166,7 @@ This event is made any time someone adds a new listener. Adds a listener to the end of the listeners array for the specified event. server.addListener('stream', function (stream) { - sys.puts("someone connected!"); + sys.puts('someone connected!'); }); @@ -130,55 +199,78 @@ A stream is an abstract interface implemented by various objects in Node. For example a request to an HTTP server is a stream, as is stdout. Streams are readable, writable, or both. All streams are instances of `EventEmitter`. -### Readable Stream +## Readable Stream A **readable stream** has the following methods, members, and events. -- Event: **`'data'`** - `callback(data)`: +### Event: 'data' + +`function (data) { }` + The `'data'` event emits either a `Buffer` (by default) or a string if `setEncoding()` was used. -- Event: **`'end'`** - `callback()`: +### Event: 'end' + +`function () { }` + Emitted when the stream has received an EOF (FIN in TCP terminology). Indicates that no more `'data'` events will happen. If the stream is also writable, it may be possible to continue writing. -- Event: **`'error'`** - `callback(exception)`: +### Event: 'error' + +`function (exception) { }` + Emitted if there was an error receiving data. -- Event: **`'close'`** - `callback()`: +### Event: 'close' + +`function () { }` + Emitted when the underlying file descriptor has be closed. Not all streams will emit this. (For example, an incoming HTTP request will not emit `'close'`.) -- **`stream.setEncoding(encoding)`**: +### stream.setEncoding(encoding) Makes the data event emit a string instead of a `Buffer`. `encoding` can be `'utf8'`, `'ascii'`, or `'binary'`. -- **`stream.pause()`**: +### stream.pause() Pauses the incoming `'data'` events. -- **`stream.resume()`**: +### stream.resume() Resumes the incoming `'data'` events after a `pause()`. -- **`stream.destroy()`**: +### stream.destroy() Closes the underlying file descriptor. Stream will not emit any more events. -### Writable Stream + + +## Writable Stream A **writable stream** has the following methods, members, and events. -- Event: **`'drain'`** - `callback()`: +### Event 'drain' + +`function () { }` + Emitted after a `write()` method was called that returned `false` to indicate that it is safe to write again. -- Event: **`'error'`** - `callback(exception)`: +### Event 'error' + +`function (exception) { }` + Emitted on error with the exception `e`. -- Event **`'close'`** - `callback()`: +### Event 'close' + +`function () { }` + Emitted when the underlying file descriptor has been closed. -- **`stream.write(string, encoding)`**: +### stream.write(string, encoding) Writes `string` with the given `encoding` to the stream. Returns `true` if the string has been flushed to the kernel buffer. Returns `false` to indicate that the kernel buffer is full, and the data will be sent out in @@ -186,20 +278,20 @@ the future. The `'drain'` event will indicate when the kernel buffer is empty again. The `encoding` defaults to `'utf8'`. -- **`stream.write(buffer)`**: +### stream.write(buffer) Same as the above except with a raw buffer. -- **`stream.end()`**: +### stream.end() Terminates the stream with EOF or FIN. -- **`stream.end(string, encoding)`**: +### stream.end(string, encoding) Sends `string` with the given `encoding` and terminates the stream with EOF or FIN. This is useful to reduce the number of packets sent. -- **`stream.end(buffer)`**: +### stream.end(buffer) Same as above but with a `buffer`. -- **`stream.destroy()`**: +### stream.destroy() Closes the underlying file descriptor. Stream will not emit any more events. @@ -207,35 +299,44 @@ Closes the underlying file descriptor. Stream will not emit any more events. These object are available in the global scope and can be accessed from anywhere. -- **`global`**: The global namespace object. +### global +The global namespace object. -- **`process`**: The process object. Most stuff lives in here. See the "process -object" section. +### process +The process object. Most stuff lives in here. See the 'process object' +section. -- **`require()`**: See the modules section. +### require() +To require modules. See the modules section. -- **`require.paths`**: The search path for absolute path arguments to `require()`. +### require.paths +The search path for absolute path arguments to `require()`. -- **`__filename`**: The filename of the script being executed. +### __filename +The filename of the script being executed. -- **`__dirname`**: The dirname of the script being executed. +### __dirname +The dirname of the script being executed. -- **`module`**: A reference to the current module (of type -`process.Module`). In particular `module.exports` is the same as the -`exports` object. See `src/process.js` for more information. +### module +A reference to the current module (of type `process.Module`). In particular +`module.exports` is the same as the `exports` object. See `src/process.js` +for more information. ## process The `process` object is a global object and can be accessed from anywhere. -It is an instance of `EventEmitter` and has the following events: +It is an instance of `EventEmitter`. -### Event: 'exit' - callback() +### Event: 'exit' + +`function () {} ` Emitted when the process is about to exit. This is a good hook to perform constant time checks of the module's state (like for unit tests). The main -event loop will no longer be run after the "exit" callback finishes, so +event loop will no longer be run after the 'exit' callback finishes, so timers may not be scheduled. Example of listening for `exit`: @@ -244,12 +345,15 @@ Example of listening for `exit`: process.addListener('exit', function () { process.nextTick(function () { - sys.puts("This will not run"); + sys.puts('This will not run'); }); - sys.puts("About to exit."); + sys.puts('About to exit.'); }); -### Event: 'uncaughtException' - callback(err) +### Event: 'uncaughtException' + +`function (err) { } ` + Emitted when an exception bubbles all the way back to the event loop. If a listener is added for this exception, the default action (which is to print @@ -257,19 +361,19 @@ a stack trace and exit) will not occur. Example of listening for `uncaughtException`: - var sys = require("sys"); + var sys = require('sys'); process.addListener('uncaughtException', function (err) { - sys.puts("Caught exception: " + err); + sys.puts('Caught exception: ' + err); }); setTimeout(function () { - sys.puts("This will still run."); + sys.puts('This will still run.'); }, 500); // Intentionally cause an exception, but don't catch it. nonexistantFunc(); - sys.puts("This will not run."); + sys.puts('This will not run.'); Note that `uncaughtException` is a very crude mechanism for exception handling. Using try / catch in your program will give you more control over @@ -277,18 +381,20 @@ your program's flow. Especially for server programs that are designed to stay running forever, `uncaughtException` can be a useful safety mechanism. -### Event: 'SIGINT' - callback() +### Signal Events: 'SIGINT' + +`function () {}` Emitted when the processes receives a signal. See sigaction(2) for a list of standard POSIX signal names such as SIGINT, SIGUSR1, etc. Example of listening for `SIGINT`: - var sys = require("sys"), + var sys = require('sys'), stdin = process.openStdin(); process.addListener('SIGINT', function () { - sys.puts("Got SIGINT. Press Control-D to exit."); + sys.puts('Got SIGINT. Press Control-D to exit.'); }); An easy way to send the `SIGINT` signal is with `Control-C` in most terminal @@ -317,11 +423,11 @@ Example of opening standard input and listening for both events: stdin.setEncoding('utf8'); stdin.addListener('data', function (chunk) { - process.stdout.write("data: " + chunk); + process.stdout.write('data: ' + chunk); }); stdin.addListener('end', function () { - process.stdout.write("end"); + process.stdout.write('end'); }); @@ -332,10 +438,10 @@ An array containing the command line arguments. The first element will be next elements will be any additional command line arguments. // print process.argv - var sys = require("sys"); + var sys = require('sys'); process.argv.forEach(function (val, index, array) { - sys.puts(index + ": " + val); + sys.puts(index + ': ' + val); }); This will generate: @@ -355,13 +461,13 @@ Changes the current working directory of the process or throws an exception if t var sys = require('sys'); - sys.puts("Starting directory: " + process.cwd()); + sys.puts('Starting directory: ' + process.cwd()); try { - process.chdir("/tmp"); - sys.puts("New directory: " + process.cwd()); + process.chdir('/tmp'); + sys.puts('New directory: ' + process.cwd()); } catch (err) { - sys.puts("chdir: " + err); + sys.puts('chdir: ' + err); } @@ -373,14 +479,14 @@ will be used as a filename if a stack trace is generated by the compiled code. Example of using `process.compile` and `eval` to run the same code: - var sys = require("sys"), + var sys = require('sys'), localVar = 123, compiled, evaled; - compiled = process.compile("localVar = 1;", "myfile.js"); - sys.puts("localVar: " + localVar + ", compiled: " + compiled); - evaled = eval("localVar = 1;"); - sys.puts("localVar: " + localVar + ", evaled: " + evaled); + compiled = process.compile('localVar = 1;', 'myfile.js'); + sys.puts('localVar: ' + localVar + ', compiled: ' + compiled); + evaled = eval('localVar = 1;'); + sys.puts('localVar: ' + localVar + ', evaled: ' + evaled); // localVar: 123, compiled: 1 // localVar: 1, evaled: 1 @@ -395,7 +501,7 @@ See also: `process.evalcx` Returns the current working directory of the process. - require('sys').puts("Current directory: " + process.cwd()); + require('sys').puts('Current directory: ' + process.cwd()); ### process.env @@ -403,10 +509,10 @@ Returns the current working directory of the process. An object containing the user environment. See environ(7). // print process.env - var sys = require("sys"); + var sys = require('sys'); Object.getOwnPropertyNames(process.env).forEach(function (val, index, array) { - sys.puts(index + ": " + val + "=" + process.env[val]); + sys.puts(index + ': ' + val + '=' + process.env[val]); }); @@ -417,13 +523,13 @@ Similar to `eval` and `process.compile`. `process.evalcx` compiles `code` to ru as if it were loaded from `filename`. The object `sandbox` will be used as the global object for `code`. `sandbox` and `filename` are optional. - var sys = require("sys"), + var sys = require('sys'), sandbox = { - animal: "cat", + animal: 'cat', count: 2 }; - process.evalcx('count += 1; name = "kitty"', sandbox, "myfile.js"); + process.evalcx('count += 1; name = 'kitty'', sandbox, 'myfile.js'); sys.puts(sys.inspect(sandbox)); Note that running untrusted code is a tricky business requiring great care. To prevent accidental @@ -435,9 +541,9 @@ must be taken. ### process.exit(code) Ends the process with the specified `code`. If omitted, exit uses the -"success" code `0`. +'success' code `0`. -To exit with a "failure" code: +To exit with a 'failure' code: process.exit(1); @@ -450,13 +556,13 @@ Gets/sets the group identity of the process. (See setgid(2).) This is the numer var sys = require('sys'); - sys.puts("Current gid: " + process.getgid()); + sys.puts('Current gid: ' + process.getgid()); try { process.setgid(501); - sys.puts("New gid: " + process.getgid()); + sys.puts('New gid: ' + process.getgid()); } catch (err) { - sys.puts("Failed to set gid: " + err); + sys.puts('Failed to set gid: ' + err); } @@ -466,13 +572,13 @@ Gets/sets the user identity of the process. (See setuid(2).) This is the numeri var sys = require('sys'); - sys.puts("Current uid: " + process.getuid()); + sys.puts('Current uid: ' + process.getuid()); try { process.setuid(501); - sys.puts("New uid: " + process.getuid()); + sys.puts('New uid: ' + process.getuid()); } catch (err) { - sys.puts("Failed to set uid: " + err); + sys.puts('Failed to set uid: ' + err); } @@ -480,14 +586,14 @@ Gets/sets the user identity of the process. (See setuid(2).) This is the numeri A compiled-in property that exposes `NODE_PREFIX`. - require("sys").puts("Install prefix: " + process.installPrefix); + require('sys').puts('Install prefix: ' + process.installPrefix); ### process.kill(pid, signal) Send a signal to a process. `pid` is the process id and `signal` is the string describing the signal to send. Signal names are strings like -"SIGINT" or "SIGUSR1". If omitted, the signal will be "SIGINT". +'SIGINT' or 'SIGUSR1'. If omitted, the signal will be 'SIGINT'. See kill(2) for more information. Note that just because the name of this function is `process.kill`, it is @@ -496,39 +602,39 @@ may do something other than kill the target process. Example of sending a signal to yourself: - var sys = require("sys"); + var sys = require('sys'); process.addListener('SIGHUP', function () { - sys.puts("Got SIGHUP signal."); + sys.puts('Got SIGHUP signal.'); }); setTimeout(function () { - sys.puts("Exiting."); + sys.puts('Exiting.'); process.exit(0); }, 100); - process.kill(process.pid, "SIGHUP"); + process.kill(process.pid, 'SIGHUP'); ### process.pid The PID of the process. - require("sys").puts("This process is pid " + process.pid); + require('sys').puts('This process is pid ' + process.pid); ### process.platform -What platform you're running on. `"linux2"`, `"darwin"`, etc. +What platform you're running on. `'linux2'`, `'darwin'`, etc. - require("sys").puts("This platform is " + process.platform); + require('sys').puts('This platform is ' + process.platform); ### process.memoryUsage() Returns an object describing the memory usage of the Node process. - var sys = require("sys"); + var sys = require('sys'); sys.puts(sys.inspect(process.memoryUsage())); @@ -549,10 +655,10 @@ On the next loop around the event loop call this callback. This is *not* a simple alias to `setTimeout(fn, 0)`, it's much more efficient. - var sys = require("sys"); + var sys = require('sys'); process.nextTick(function () { - sys.puts("nextTick callback"); + sys.puts('nextTick callback'); }); @@ -567,46 +673,46 @@ given, otherwise returns the current mask. oldmask = process.umask(newmask); // these octal numbers don't display right in JavaScript - sys.puts("Changed umask from: " + oldmask + " to " + newmask); + sys.puts('Changed umask from: ' + oldmask + ' to ' + newmask); ## sys -These functions are in the module `"sys"`. Use `require("sys")` to access +These functions are in the module `'sys'`. Use `require('sys')` to access them. -### puts(string) +### sys.puts(string) Outputs `string` and a trailing new-line to `stdout`. - require("sys").puts("String with a newline"); - + require('sys').puts('String with a newline'); -### print(string) + +### sys.print(string) Like `puts()` but without the trailing new-line. - require("sys").print("String with no newline"); + require('sys').print('String with no newline'); -### debug(string) +### sys.debug(string) A synchronous output function. Will block the process and output `string` immediately to `stderr`. - require("sys").debug("message on stderr"); + require('sys').debug('message on stderr'); -### log(string) +### sys.log(string) Output with timestamp on `stdout`. - require("sys").log("Timestmaped message."); + require('sys').log('Timestmaped message.'); -### inspect(object, showHidden, depth) +### sys.inspect(object, showHidden, depth) Return a string representation of `object`, which is useful for debugging. @@ -621,81 +727,13 @@ in `null` for `depth`. Example of inspecting all properties of the `sys` object: - var sys = require("sys"); + var sys = require('sys'); sys.puts(sys.inspect(sys, true, null)); - - - -## Modules - -Node uses the CommonJS module system. - -Node has a simple module loading system. In Node, files and modules are in -one-to-one correspondence. As an example, `foo.js` loads the module -`circle.js` in the same directory. - -The contents of `foo.js`: - - var circle = require("./circle"), - var sys = require("sys"); - sys.puts( "The area of a circle of radius 4 is " - + circle.area(4)); - -The contents of `circle.js`: - - var PI = 3.14; - - exports.area = function (r) { - return PI * r * r; - }; - - exports.circumference = function (r) { - return 2 * PI * r; - }; - -The module `circle.js` has exported the functions `area()` and -`circumference()`. To export an object, add to the special `exports` -object. (Alternatively, one can use `this` instead of `exports`.) Variables -local to the module will be private. In this example the variable `PI` is -private to `circle.js`. The function `puts()` comes from the module `"sys"`, -which is a built-in module. Modules which are not prefixed by `"./"` are -built-in module--more about this later. - -A module prefixed with `"./"` is relative to the file calling `require()`. -That is, `circle.js` must be in the same directory as `foo.js` for -`require("./circle")` to find it. - -Without the leading `"./"`, like `require("assert")` the module is searched -for in the `require.paths` array. `require.paths` on my system looks like -this: - -`[ "/home/ryan/.node_libraries" ]` - -That is, when `require("assert")` is called Node looks for: - - * 1: `/home/ryan/.node_libraries/assert.js` - * 2: `/home/ryan/.node_libraries/assert.node` - * 3: `/home/ryan/.node_libraries/assert/index.js` - * 4: `/home/ryan/.node_libraries/assert/index.node` - -interrupting once a file is found. Files ending in `".node"` are binary Addon -Modules; see the section below about addons. `"index.js"` allows one to -package a module as a directory. - -`require.paths` can be modified at runtime by simply unshifting new -paths onto it, or at startup with the `NODE_PATH` environmental -variable (which should be a list of paths, colon separated). - -Use `process.mixin()` to include modules into the global namespace. - - process.mixin(GLOBAL, require("./circle"), require("sys")); - puts("The area of a circle of radius 4 is " + area(4)); - ## Timers ### setTimeout(callback, delay, [arg, ...]) @@ -703,23 +741,23 @@ Use `process.mixin()` to include modules into the global namespace. To schedule execution of `callback` after `delay` milliseconds. Returns a `timeoutId` for possible use with `clearTimeout()`. - var sys = require("sys"), + var sys = require('sys'), start = new Date(), timer = setTimeout(function () { - sys.puts("Timer fired after " + (Date.now() - start) + "ms"); + sys.puts('Timer fired after ' + (Date.now() - start) + 'ms'); }, 1000); - sys.puts("Started timer."); + sys.puts('Started timer.'); Optionally, you can pass arguments to the callback. - var sys = require("sys"), + var sys = require('sys'), start = new Date(), timer = setTimeout(function (start_time, message) { - sys.puts(message + (Date.now() - start_time) + "ms"); - }, 1000, start, "Timer fired after "); + sys.puts(message + (Date.now() - start_time) + 'ms'); + }, 1000, start, 'Timer fired after '); - sys.puts("Started timer."); + sys.puts('Started timer.'); These two examples generate the same output. @@ -727,17 +765,17 @@ These two examples generate the same output. Prevents a timeout from triggering. - var sys = require("sys"), + var sys = require('sys'), start = new Date(), timer1 = setTimeout(function () { - sys.puts("Timer fired after " + (Date.now() - start) + "ms"); + sys.puts('Timer fired after ' + (Date.now() - start) + 'ms'); }, 5000), timer2 = setTimeout(function () { - sys.puts("This is taking too long. Stopping timer1."); + sys.puts('This is taking too long. Stopping timer1.'); clearTimeout(timer1); }, 1000); - sys.puts("Started timers."); + sys.puts('Started timers.'); ### setInterval(callback, delay, [arg, ...]) @@ -749,18 +787,18 @@ Optionally, you can also pass arguments to the callback. Stops a interval from triggering. - var sys = require("sys"), + var sys = require('sys'), start = new Date(), count = 10, timer = setInterval(function () { count -= 1; - sys.puts("Timer fired after " + (Date.now() - start) + "ms " + count + " remaining."); + sys.puts('Timer fired after ' + (Date.now() - start) + 'ms ' + count + ' remaining.'); if (count === 0) { clearInterval(timer); } }, 100); - sys.puts("Started timer."); + sys.puts('Started timer.'); ## Child Processes @@ -771,17 +809,20 @@ class. It is possible to stream data through the child's `stdin`, `stdout`, and `stderr` in a fully non-blocking way. -To create a child process use `require("child_process").spawn()`. +To create a child process use `require('child_process').spawn()`. Child processes always have three streams associated with them. `child.stdin`, `child.stdout`, and `child.stderr`. -`ChildProcess` is an EventEmitter with the following events: +`ChildProcess` is an EventEmitter. - - **`exit`** - `callback(code)`: - This event is emitted after the child process ends. `code` is the final - exit code of the process. After this event is emitted, the `"output"` - and `"error"` callbacks will no longer be made. +### Event 'exit' + +`function (code) {} ` + +This event is emitted after the child process ends. `code` is the final exit +code of the process. After this event is emitted, the `'output'` and +`'error'` callbacks will no longer be made. ### child_process.spawn(command, args, env) @@ -792,32 +833,32 @@ defaults to `process.env`. Example of running `ls -lh /usr`, capturing `stdout`, `stderr`, and the exit code: - var sys = require("sys"), - spawn = require("child_process").spawn, - ls = spawn("ls", ["-lh", "/usr"]); + var sys = require('sys'), + spawn = require('child_process').spawn, + ls = spawn('ls', ['-lh', '/usr']); - ls.stdout.addListener("data", function (data) { - sys.print("stdout: " + data); + ls.stdout.addListener('data', function (data) { + sys.print('stdout: ' + data); }); - ls.stderr.addListener("data", function (data) { - sys.print("stderr: " + data); + ls.stderr.addListener('data', function (data) { + sys.print('stderr: ' + data); }); - ls.addListener("exit", function (code) { - sys.puts("child process exited with code " + code); + ls.addListener('exit', function (code) { + sys.puts('child process exited with code ' + code); }); Example of checking for failed exec: - var sys = require("sys"), - spawn = require("child_process").spawn, - child = spawn("bad_command"); + var sys = require('sys'), + spawn = require('child_process').spawn, + child = spawn('bad_command'); - child.stderr.addListener("data", function (data) { + child.stderr.addListener('data', function (data) { if (/^execvp\(\)/.test(data.asciiSlice(0,data.length))) { - sys.puts("Failed to start child process."); + sys.puts('Failed to start child process.'); } }); @@ -828,18 +869,18 @@ See also: `child_process.exec()` ### child.kill(signal) Send a signal to the child process. If no argument is given, the process will -be sent `"SIGTERM"`. See `signal(7)` for a list of available signals. +be sent `'SIGTERM'`. See `signal(7)` for a list of available signals. - var sys = require("sys"), - spawn = require("child_process").spawn, - grep = spawn("grep", ["ssh"]); + var sys = require('sys'), + spawn = require('child_process').spawn, + grep = spawn('grep', ['ssh']); - grep.addListener("exit", function (code) { - sys.puts("child process exited with code " + code); + grep.addListener('exit', function (code) { + sys.puts('child process exited with code ' + code); }); // send SIGHUP to process - grep.kill("SIGHUP"); + grep.kill('SIGHUP'); Note that while the function is called `kill`, the signal delivered to the child process may not actually kill it. `kill` really just sends a signal to a process. @@ -853,53 +894,53 @@ The PID of the child process. Example: - var sys = require("sys"), - spawn = require("child_process").spawn, - grep = spawn("grep", ["ssh"]); + var sys = require('sys'), + spawn = require('child_process').spawn, + grep = spawn('grep', ['ssh']); - sys.puts("Spawned child pid: " + grep.pid); + sys.puts('Spawned child pid: ' + grep.pid); grep.stdin.close(); ### child.stdin.write(data, encoding) Write data to the child process's `stdin`. The second argument is optional and -specifies the encoding: possible values are `"utf8"`, `"ascii"`, and -`"binary"`. +specifies the encoding: possible values are `'utf8'`, `'ascii'`, and +`'binary'`. -Example: A very elaborate way to run "ps ax | grep ssh" +Example: A very elaborate way to run 'ps ax | grep ssh' - var sys = require("sys"), - spawn = require("child_process").spawn, - ps = spawn("ps", ["ax"]), - grep = spawn("grep", ["ssh"]); + var sys = require('sys'), + spawn = require('child_process').spawn, + ps = spawn('ps', ['ax']), + grep = spawn('grep', ['ssh']); - ps.stdout.addListener("data", function (data) { + ps.stdout.addListener('data', function (data) { grep.stdin.write(data); }); - ps.stderr.addListener("data", function (data) { - sys.print("ps stderr: " + data); + ps.stderr.addListener('data', function (data) { + sys.print('ps stderr: ' + data); }); - ps.addListener("exit", function (code) { + ps.addListener('exit', function (code) { if (code !== 0) { - sys.puts("ps process exited with code " + code); + sys.puts('ps process exited with code ' + code); } grep.stdin.close(); }); - grep.stdout.addListener("data", function (data) { + grep.stdout.addListener('data', function (data) { sys.print(data); }); - grep.stderr.addListener("data", function (data) { - sys.print("grep stderr: " + data); + grep.stderr.addListener('data', function (data) { + sys.print('grep stderr: ' + data); }); - grep.addListener("exit", function (code) { + grep.addListener('exit', function (code) { if (code !== 0) { - sys.puts("grep process exited with code " + code); + sys.puts('grep process exited with code ' + code); } }); @@ -910,12 +951,12 @@ Closes the child process's `stdin` stream. This often causes the child process Example: - var sys = require("sys"), - spawn = require("child_process").spawn, - grep = spawn("grep", ["ssh"]); + var sys = require('sys'), + spawn = require('child_process').spawn, + grep = spawn('grep', ['ssh']); - grep.addListener("exit", function (code) { - sys.puts("child process exited with code " + code); + grep.addListener('exit', function (code) { + sys.puts('child process exited with code ' + code); }); grep.stdin.close(); @@ -926,15 +967,15 @@ Example: High-level way to execute a command as a child process, buffer the output, and return it all in a callback. - var sys = require("sys"), - exec = require("child_process").exec, + var sys = require('sys'), + exec = require('child_process').exec, child; - - child = exec("cat *.js bad_file | wc -l", function (error, stdout, stderr) { - sys.print("stdout: " + stdout); - sys.print("stderr: " + stderr); + + child = exec('cat *.js bad_file | wc -l', function (error, stdout, stderr) { + sys.print('stdout: ' + stdout); + sys.print('stderr: ' + stderr); if (error !== null) { - sys.puts("exec error: " + error); + sys.puts('exec error: ' + error); } }); @@ -947,7 +988,7 @@ will be the exit code of the child process. ## File System File I/O is provided by simple wrappers around standard POSIX functions. To -use this module do `require("fs")`. All the methods have asynchronous and +use this module do `require('fs')`. All the methods have asynchronous and synchronous forms. The asynchronous form always take a completion callback as its last argument. @@ -957,42 +998,42 @@ completed successfully, then the first argument will be `null` or `undefined`. Here is an example of the asynchronous version: - var fs = require("fs"), - sys = require("sys"); + var fs = require('fs'), + sys = require('sys'); - fs.unlink("/tmp/hello", function (err) { + fs.unlink('/tmp/hello', function (err) { if (err) throw err; - sys.puts("successfully deleted /tmp/hello"); + sys.puts('successfully deleted /tmp/hello'); }); Here is the synchronous version: - var fs = require("fs"), - sys = require("sys"); + var fs = require('fs'), + sys = require('sys'); - fs.unlinkSync("/tmp/hello") - sys.puts("successfully deleted /tmp/hello"); + fs.unlinkSync('/tmp/hello') + sys.puts('successfully deleted /tmp/hello'); With the asynchronous methods there is no guaranteed ordering. So the following is prone to error: - fs.rename("/tmp/hello", "/tmp/world", function (err) { + fs.rename('/tmp/hello', '/tmp/world', function (err) { if (err) throw err; - sys.puts("renamed complete"); + sys.puts('renamed complete'); }); - fs.stat("/tmp/world", function (err, stats) { + fs.stat('/tmp/world', function (err, stats) { if (err) throw err; - sys.puts("stats: " + JSON.stringify(stats)); + sys.puts('stats: ' + JSON.stringify(stats)); }); It could be that `fs.stat` is executed before `fs.rename`. The correct way to do this is to chain the callbacks. - fs.rename("/tmp/hello", "/tmp/world", function (err) { + fs.rename('/tmp/hello', '/tmp/world', function (err) { if (err) throw err; - fs.stat("/tmp/world", function (err, stats) { + fs.stat('/tmp/world', function (err, stats) { if (err) throw err; - sys.puts("stats: " + JSON.stringify(stats)); + sys.puts('stats: ' + JSON.stringify(stats)); }); }); @@ -1038,9 +1079,9 @@ Asynchronous stat(2) or lstat(2). The callback gets two arguments `(err, stats)` , size: 4096 , blksize: 4096 , blocks: 8 - , atime: "2009-06-29T11:11:55Z" - , mtime: "2009-06-29T11:11:40Z" - , ctime: "2009-06-29T11:11:40Z" + , atime: '2009-06-29T11:11:55Z' + , mtime: '2009-06-29T11:11:40Z' + , ctime: '2009-06-29T11:11:40Z' } See the `fs.Stats` section below for more information. @@ -1109,12 +1150,12 @@ Synchronous mkdir(2). Asynchronous readdir(3). Reads the contents of a directory. The callback gets two arguments `(err, files)` where `files` is an array of -the names of the files in the directory excluding `"."` and `".."`. +the names of the files in the directory excluding `'.'` and `'..'`. ### fs.readdirSync(path) -Synchronous readdir(3). Returns an array of filenames excluding `"."` and -`".."`. +Synchronous readdir(3). Returns an array of filenames excluding `'.'` and +`'..'`. ### fs.close(fd, callback) @@ -1126,8 +1167,8 @@ Synchronous close(2). ### fs.open(path, flags, mode, callback) -Asynchronous file open. See open(2). Flags can be "r", "r+", "w", "w+", "a", -or "a+". The callback gets two arguments `(err, fd)`. +Asynchronous file open. See open(2). Flags can be 'r', 'r+', 'w', 'w+', 'a', +or 'a+'. The callback gets two arguments `(err, fd)`. ### fs.openSync(path, flags, mode) @@ -1162,11 +1203,11 @@ is a string--what was read--and `bytesRead` is the number of bytes read. Synchronous version of `fs.read`. Returns an array `[data, bytesRead]`. -### fs.readFile(filename, encoding="utf8", callback) +### fs.readFile(filename, encoding='utf8', callback) Asynchronously reads the entire contents of a file. Example: - fs.readFile("/etc/passwd", function (err, data) { + fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; sys.puts(data); }); @@ -1174,20 +1215,20 @@ Asynchronously reads the entire contents of a file. Example: The callback is passed two arguments `(err, data)`, where `data` is the contents of the file. -### fs.readFileSync(filename, encoding="utf8") +### fs.readFileSync(filename, encoding='utf8') Synchronous version of `fs.readFile`. Returns the contents of the `filename`. -### fs.writeFile(filename, data, encoding="utf8", callback) +### fs.writeFile(filename, data, encoding='utf8', callback) Asynchronously writes data to a file. Example: - fs.writeFile("message.txt", "Hello Node", function (err) { + fs.writeFile('message.txt', 'Hello Node', function (err) { if (err) throw err; - sys.puts("It's saved!"); + sys.puts('It's saved!'); }); -### fs.writeFileSync(filename, data, encoding="utf8") +### fs.writeFileSync(filename, data, encoding='utf8') The synchronous version of `fs.writeFile`. @@ -1204,8 +1245,8 @@ The `listener` gets two arguments the current stat object and the previous stat object: fs.watchFile(f, function (curr, prev) { - sys.puts("the current mtime is: " + curr.mtime); - sys.puts("the previous mtime was: " + prev.mtime); + sys.puts('the current mtime is: ' + curr.mtime); + sys.puts('the previous mtime was: ' + prev.mtime); }); These stat objects are instances of `fs.Stat`. @@ -1214,7 +1255,7 @@ These stat objects are instances of `fs.Stat`. Stop watching for changes on `filename`. -### fs.Stats +## fs.Stats Objects returned from `fs.stat()` and `fs.lstat()` are of this type. @@ -1226,15 +1267,10 @@ Objects returned from `fs.stat()` and `fs.lstat()` are of this type. - `stats.isFIFO()` - `stats.isSocket()` -### fs.FileReadStream -This is an EventEmitter with the following events. +## fs.FileReadStream - - **`"open"`** `callback(fd)` The file descriptor was opened. - - **`"data"`** `callback(chunk)` A chunk of data was read. - - **`"error"`** `callback(err)` An error occurred. This stops the stream. - - **`"end"`** `callback()` The end of the file was reached. - - **`"close"`** `callback()` The file descriptor was closed. +`FileReadStream` is a readable stream. ### fs.createReadStream(path, [options]) @@ -1242,20 +1278,20 @@ Returns a new FileReadStream object. `options` is an object with the following defaults: - { "flags": "r" - , "encoding": "binary" - , "mode": 0666 - , "bufferSize": 4 * 1024 + { 'flags': 'r' + , 'encoding': 'binary' + , 'mode': 0666 + , 'bufferSize': 4 * 1024 } ### readStream.readable -A boolean that is `true` by default, but turns `false` after an `"error"` -occured, the stream came to an "end", or `destroy()` was called. +A boolean that is `true` by default, but turns `false` after an `'error'` +occured, the stream came to an 'end', or `destroy()` was called. ### readStream.pause() -Stops the stream from reading further data. No `"data"` event will be fired +Stops the stream from reading further data. No `'data'` event will be fired until the stream is resumed. ### readStream.resume() @@ -1264,35 +1300,32 @@ Resumes the stream. Together with `pause()` this useful to throttle reading. ### readStream.destroy() -Allows to close the stream before the `"end"` is reached. No more events other -than `"close"` will be fired after this method has been called. +Allows to close the stream before the `'end'` is reached. No more events other +than `'close'` will be fired after this method has been called. -### fs.FileWriteStream +## fs.FileWriteStream -- **`"open"`**`(fd)` The file descriptor was opened. -- **`"drain"`**`()` No more data needs to be written. -- **`"error"`**`(err)` An error occurred. This stops the stream. -- **`"close"`**`()` The file descriptor was closed. +`FileWriteStream` is a writable stream. ### fs.createWriteStream(path, [options]) Returns a new FileWriteStream object. `options` is an object with the following defaults: - { "flags": "w" - , "encoding": "binary" - , "mode": 0666 + { 'flags': 'w' + , 'encoding': 'binary' + , 'mode': 0666 } ### writeStream.writeable -A boolean that is `true` by default, but turns `false` after an `"error"` +A boolean that is `true` by default, but turns `false` after an `'error'` occurred or `end()` / `destroy()` was called. ### writeStream.write(data) Returns `true` if the data was flushed to the kernel, and `false` if it was -queued up for being written later. A `"drain"` will fire after all queued data +queued up for being written later. A `'drain'` will fire after all queued data has been written. You can also specify `callback` to be notified when the data from this write @@ -1308,7 +1341,7 @@ Allows to close the stream regardless of its current state. ## HTTP -To use the HTTP server and client one must `require("http")`. +To use the HTTP server and client one must `require('http')`. The HTTP interfaces in Node are designed to support many features of the protocol which have been traditionally difficult to use. @@ -1318,10 +1351,10 @@ user is able to stream data. HTTP message headers are represented by an object like this: - { "content-length": "123" - , "content-type": "text/plain" - , "stream": "keep-alive" - , "accept": "*/*" + { 'content-length': '123' + , 'content-type': 'text/plain' + , 'stream': 'keep-alive' + , 'accept': '*/*' } Keys are lowercased. Values are not modified. @@ -1332,24 +1365,31 @@ parsing only. It parses a message into headers and body but it does not parse the actual headers or the body. -### http.Server +## http.Server This is an EventEmitter with the following events: - - **`"request"`** - `callback(request, response)`: +### Event: 'request' + +`function (request, response) { }` + `request` is an instance of `http.ServerRequest` and `response` is an instance of `http.ServerResponse` - - **`"stream"`** - `callback(stream)`: +### Event: 'stream' + +`function (stream) { }` + When a new TCP stream is established. `stream` is an object of type `http.Connection`. Usually users will not want to access this event. The `stream` can also be accessed at `request.stream`. - - **`"close"`** - `callback(errno)`: - Emitted when the server closes. `errorno` is an integer which indicates what, if any, - error caused the server to close. If no - error occured `errorno` will be 0. +### Event: 'close' + +`function (errno) { }` + + Emitted when the server closes. ### http.createServer(request_listener, [options]) @@ -1361,7 +1401,7 @@ The `options` argument is optional. The options argument for `net.Server`. The `request_listener` is a function which is automatically -added to the `"request"` event. +added to the `'request'` event. ### server.listen(port, hostname) @@ -1387,14 +1427,14 @@ is ready to accept connections. Stops the server from accepting new connections. -### http.ServerRequest +## http.ServerRequest This object is created internally by a HTTP server--not by -the user--and passed as the first argument to a `"request"` listener. +the user--and passed as the first argument to a `'request'` listener. This is an EventEmitter with the following events: -- **`"data"`** - `callback(chunk)`: +- **`'data'`** - `callback(chunk)`: Emitted when a piece of the message body is received. Example: A chunk of the body is given as the single @@ -1402,7 +1442,7 @@ argument. The transfer-encoding has been decoded. The body chunk is a string. The body encoding is set with `request.setBodyEncoding()`. -- **`"end"`** - `callback()`: +- **`'end'`** - `callback()`: Emitted exactly once for each message. No arguments. After emitted no other events will be emitted on the request. @@ -1410,7 +1450,7 @@ emitted no other events will be emitted on the request. ### request.method The request method as a string. Read only. Example: -`"GET"`, `"DELETE"`. +`'GET'`, `'DELETE'`. ### request.url @@ -1424,12 +1464,12 @@ present in the actual HTTP request. If the request is: Then `request.url` will be: - "/status?name=ryan" + '/status?name=ryan' If you would like to parse the URL into its parts, you can use -`require("url").parse(request.url)`. Example: +`require('url').parse(request.url)`. Example: - node> require("url").parse("/status?name=ryan") + node> require('url').parse('/status?name=ryan') { href: '/status?name=ryan' , search: '?name=ryan' , query: 'name=ryan' @@ -1437,10 +1477,10 @@ If you would like to parse the URL into its parts, you can use } If you would like to extract the params from the query string, -you can use the `require("querystring").parse` function, or pass -`true` as the second argument to `require("url").parse`. Example: +you can use the `require('querystring').parse` function, or pass +`true` as the second argument to `require('url').parse`. Example: - node> require("url").parse("/status?name=ryan", true) + node> require('url').parse('/status?name=ryan', true) { href: '/status?name=ryan' , search: '?name=ryan' , query: { name: 'ryan' } @@ -1456,13 +1496,13 @@ Read only. ### request.httpVersion The HTTP protocol version as a string. Read only. Examples: -`"1.1"`, `"1.0"` +`'1.1'`, `'1.0'` -### request.setEncoding(encoding="binary") +### request.setEncoding(encoding='binary') -Set the encoding for the request body. Either `"utf8"` or `"binary"`. Defaults -to `"binary"`. +Set the encoding for the request body. Either `'utf8'` or `'binary'`. Defaults +to `'binary'`. ### request.pause() @@ -1474,14 +1514,15 @@ Pauses request from emitting events. Useful to throttle back an upload. Resumes a paused request. -### request.stream +### request.connection -The `http.Connection` object. +The `net.Stream` object assocated with the connection. -### http.ServerResponse + +## http.ServerResponse This object is created internally by a HTTP server--not by the user. It is -passed as the second parameter to the `"request"` event. +passed as the second parameter to the `'request'` event. It is a writable stream. ### response.writeHead(statusCode[, reasonPhrase] , headers) @@ -1492,16 +1533,16 @@ argument. Example: - var body = "hello world"; + var body = 'hello world'; response.writeHead(200, { - "Content-Length": body.length, - "Content-Type": "text/plain" + 'Content-Length': body.length, + 'Content-Type': 'text/plain' }); This method must only be called once on a message and it must be called before `response.end()` is called. -### response.write(chunk, encoding="ascii") +### response.write(chunk, encoding) This method must be called after `writeHead` was called. It sends a chunk of the response body. This method may @@ -1509,7 +1550,7 @@ be called multiple times to provide successive parts of the body. If `chunk` is a string, the second parameter specifies how to encode it into a byte stream. By default the -`encoding` is `"ascii"`. +`encoding` is `'ascii'`. **Note**: This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used. @@ -1528,7 +1569,7 @@ has been sent; that server should consider this message complete. The method, `response.end()`, MUST be called on each response. -### http.Client +## http.Client An HTTP client is constructed with a server address as its argument, the returned handle is then used to issue one or more @@ -1538,16 +1579,16 @@ stream. _Currently the implementation does not pipeline requests._ Example of connecting to `google.com`: - var sys = require("sys"), - http = require("http"); - var google = http.createClient(80, "www.google.com"); - var request = google.request("GET", "/", {"host": "www.google.com"}); + var sys = require('sys'), + http = require('http'); + var google = http.createClient(80, 'www.google.com'); + var request = google.request('GET', '/', {'host': 'www.google.com'}); request.addListener('response', function (response) { - sys.puts("STATUS: " + response.statusCode); - sys.puts("HEADERS: " + JSON.stringify(response.headers)); - response.setEncoding("utf8"); + sys.puts('STATUS: ' + response.statusCode); + sys.puts('HEADERS: ' + JSON.stringify(response.headers)); + response.setEncoding('utf8'); response.addListener('data', function (chunk) { - sys.puts("BODY: " + chunk); + sys.puts('BODY: ' + chunk); }); }); request.end(); @@ -1563,7 +1604,7 @@ stream is not established until a request is issued. Issues a request; if necessary establishes stream. Returns a `http.ClientRequest` instance. -`method` is optional and defaults to "GET" if omitted. +`method` is optional and defaults to 'GET' if omitted. `request_headers` is optional. Additional request headers might be added internally @@ -1580,10 +1621,10 @@ the user to stream a body to the server with `request.write()`.) -### http.ClientRequest +## http.ClientRequest -This object is created internally and returned from the request methods of a -`http.Client`. It represents an _in-progress_ request whose header has +This object is created internally and returned from the `request()` method +of a `http.Client`. It represents an _in-progress_ request whose header has already been sent. To get the response, add a listener for `'response'` to the request object. @@ -1592,7 +1633,7 @@ headers have been received. The `'response'` event is executed with one argument which is an instance of `http.ClientResponse`. During the `'response'` event, one can add listeners to the -response object; particularly to listen for the `"data"` event. Note that +response object; particularly to listen for the `'data'` event. Note that the `'response'` event is called before any part of the response body is received, so there is no need to worry about racing to catch the first part of the body. As long as a listener for `'data'` is added during the `'response'` @@ -1602,7 +1643,7 @@ event, the entire body will be caught. // Good request.addListener('response', function (response) { response.addListener('data', function (chunk) { - sys.puts("BODY: " + chunk); + sys.puts('BODY: ' + chunk); }); }); @@ -1610,24 +1651,25 @@ event, the entire body will be caught. request.addListener('response', function (response) { setTimeout(function () { response.addListener('data', function (chunk) { - sys.puts("BODY: " + chunk); + sys.puts('BODY: ' + chunk); }); }, 10); }); +This is a writable stream. This is an `EventEmitter` with the following events: -- **`"response"`** - `callback(response)`: +- **`'response'`** - `callback(response)`: Emitted when a response is received to this request. This event is emitted only once. The `response` argument will be an instance of `http.ClientResponse`. -### request.write(chunk, encoding="ascii") +### request.write(chunk, encoding='ascii') Sends a chunk of the body. By calling this method many times, the user can stream a request body to a server--in that case it is suggested to use the -`["Transfer-Encoding", "chunked"]` header line when +`['Transfer-Encoding', 'chunked']` header line when creating the request. The `chunk` argument should be an array of integers @@ -1635,25 +1677,29 @@ or a string. The `encoding` argument is optional and only applies when `chunk` is a string. The encoding -argument should be either `"utf8"` or -`"ascii"`. By default the body uses ASCII encoding, +argument should be either `'utf8'` or +`'ascii'`. By default the body uses ASCII encoding, as it is faster. ### request.end() Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is -chunked, this will send the terminating `"0\r\n\r\n"`. +chunked, this will send the terminating `'0\r\n\r\n'`. -### http.ClientResponse +## http.ClientResponse -This object is created internally and passed to the `"response"` event. +This object is created when making a request with `http.Client`. It is +passed to the `'response'` event of the request object. -This is an `EventEmitter` with the following events. +The response implements the stream interface. + +### Event 'data' + +`function (chunk) {}` -- **`"data"`** - `callback(chunk)`: Emitted when a piece of the message body is received. Example: A chunk of the body is given as the single @@ -1661,7 +1707,10 @@ Emitted when a piece of the message body is received. body chunk a String. The body encoding is set with `response.setBodyEncoding()`. -- **`"end"`** - `callback()`: +### Event: 'end' + +`function () {}` + Emitted exactly once for each message. No arguments. After emitted no other events will be emitted on the response. @@ -1672,7 +1721,7 @@ The 3-digit HTTP response status code. E.G. `404`. ### response.httpVersion The HTTP version of the connected-to server. Probably either -`"1.1"` or `"1.0"`. +`'1.1'` or `'1.0'`. ### response.headers @@ -1680,8 +1729,8 @@ The response headers. ### response.setEncoding(encoding) -Set the encoding for the response body. Either `"utf8"` or `"binary"`. -Defaults to `"binary"`. +Set the encoding for the response body. Either `'utf8'` or `'binary'`. +Defaults to `'binary'`. ### response.pause() @@ -1696,48 +1745,58 @@ Resumes a paused response. A reference to the `http.Client` that this response belongs to. -## Networking -Creating UNIX and TCP servers and clients. -To use networking, one must `require("net")`. +## net.Server -### net.Server +This class can be used to create a TCP or UNIX server. Here is an example of a echo server which listens for connections on port 7000: - var net = require("net"); + var net = require('net'); var server = net.createServer(function (stream) { - stream.setEncoding("utf8"); + stream.setEncoding('utf8'); stream.addListener('connect', function () { - stream.write("hello\r\n"); + stream.write('hello\r\n'); }); stream.addListener('data', function (data) { stream.write(data); }); stream.addListener('end', function () { - stream.write("goodbye\r\n"); + stream.write('goodbye\r\n'); stream.end(); }); }); - server.listen(7000, "localhost"); + server.listen(7000, 'localhost'); This is an EventEmitter with the following events: -- **`"stream"`** - `callback(stream)`: -Emitted when a new stream is made. `stream` is an instance of `net.Stream`. +### Event: 'listening' -- **`"close"`** - `callback(errno)`: -Emitted when the server closes. `errorno` is an integer which indicates what, if any, error caused -the server to close. If no error occurred `errorno` will be 0. +`function () {}` +After `listen()` is called, this event will notify that the server is ready +to accept connections. + +### Event: 'connection' + +`function (stream) {}` + +Emitted when a new connection is made. `stream` is an instance of +`net.Stream`. + +### Event: 'close' + +`function (errno) {}` + +Emitted when the server closes. `errorno` is an integer which indicates +what, if any, error caused the server to close. If no error occurred +`errorno` will be 0. ### net.createServer(connectionListener) -Creates a new TCP server. - -The `connection_listener` argument is automatically set as a listener for -the `"stream"` event. +Creates a new TCP server. The `connection_listener` argument is +automatically set as a listener for the `'connection'` event. ### server.listen(port, host=null) @@ -1754,78 +1813,107 @@ safe to connect to it. ### server.close() Stops the server from accepting new connections. This function is -asynchronous, the server is finally closed when the server emits a `"close"` +asynchronous, the server is finally closed when the server emits a `'close'` event. -### net.Stream +## net.Stream -This object is used as a TCP/UNIX client and also as a server-side stream -for `net.Server`. +This object is an abstraction of of a TCP or UNIX socket. `net.Stream` +instance implement a duplex stream interface. They can be created by the +user and used as a client (with `connect()`) or they can be created by Node +and passed to the user through the `'connection'` event of a server. -This is an EventEmitter and duplex stream with the following events: +`net.Stream` instances are an EventEmitters with the following events: + +### Event: 'connect' + +`function () { }` -- **`"connect"`** - `callback()`: Call once the stream is established after a call to `createConnection()` or `connect()`. -- **`"data"`** - `callback(data)`: +### Event: 'data' + +`function (data) { }` + Called when data is received on the stream. `data` will be a string. Encoding of data is set by `stream.setEncoding()`. -- **`"end"`** - `callback()`: +### Event: 'end' + +`function () { }` + Called when the other end of the stream sends a FIN packet. After this is emitted the `readyState` will be -`"writeOnly"`. One should probably just call +`'writeOnly'`. One should probably just call `stream.end()` when this event is emitted. -- **`"timeout"`** - `callback()`: -Emitted if the stream times out from inactivity. The -`"close"` event will be emitted immediately following this event. +### Event: 'timeout' + +`function () { }` + +Emitted if the stream times out from inactivity. The +`'close'` event will be emitted immediately following this event. + +### Event: 'drain' + +`function () { }` -- **`"drain"`** - `callback()`: Emitted when the write buffer becomes empty. Can be used to throttle uploads. -- **`"close"`** - `callback(had_error)`: +### Event: 'error' + +`function (exception) { }` + +Emitted when an error occurs. The `'close'` event will be called directly +following this event. + +### Event: 'close' + +`function () { }` + Emitted once the stream is fully closed. The argument `had_error` is a boolean which says if the stream was closed due to a transmission -error. (TODO: access error codes.) +error. -### net.createConnection(port, host="127.0.0.1") -Creates a new stream object and opens a stream to the specified `port` +### net.createConnection(port, host='127.0.0.1') + +Construct a new stream object and opens a stream to the specified `port` and `host`. If the second parameter is omitted, localhost is assumed. -When the stream is established the `"connect"` event will be emitted. +When the stream is established the `'connect'` event will be emitted. -### stream.connect(port, host="127.0.0.1") +### stream.connect(port, host='127.0.0.1') Opens a stream to the specified `port` and `host`. `createConnection()` also opens a stream; normally this method is not needed. Use this only if a stream is closed and you want to reuse the object to connect to another server. -This function is asynchronous. When the `"connect"` event is emitted the -stream is established. If there is a problem connecting, the `"connect"` -event will not be emitted, the `"close"` event will be emitted with -`had_error == true`. +This function is asynchronous. When the `'connect'` event is emitted the +stream is established. If there is a problem connecting, the `'connect'` +event will not be emitted, the `'error'` event will be emitted with +the exception. + ### stream.remoteAddress The string representation of the remote IP address. For example, -`"74.125.127.100"` or `"2001:4860:a005::68"`. +`'74.125.127.100'` or `'2001:4860:a005::68'`. This member is only present in server-side connections. ### stream.readyState -Either `"closed"`, `"open"`, `"opening"`, `"readOnly"`, or `"writeOnly"`. +Either `'closed'`, `'open'`, `'opening'`, `'readOnly'`, or `'writeOnly'`. ### stream.setEncoding(encoding) -Sets the encoding (either `"ascii"`, `"utf8"`, or `"binary"`) for data that is +Sets the encoding (either `'ascii'`, `'utf8'`, or `'binary'`) for data that is received. -### stream.write(data, encoding="ascii") +### stream.write(data, encoding='ascii') Sends data on the stream. The second parameter specifies the encoding in the case of a string--it defaults to ASCII because encoding to UTF8 is rather @@ -1839,7 +1927,7 @@ buffer. Returns `false` if all or part of the data was queued in user memory. Half-closes the stream. I.E., it sends a FIN packet. It is possible the server will still send some data. After calling this `readyState` will be -`"readOnly"`. +`'readOnly'`. ### stream.destroy() @@ -1848,7 +1936,7 @@ case of errors (parse error or so). ### stream.pause() -Pauses the reading of data. That is, `"data"` events will not be emitted. +Pauses the reading of data. That is, `'data'` events will not be emitted. Useful to throttle back an upload. ### stream.resume() @@ -1872,26 +1960,26 @@ immediately fire off data each time `stream.write()` is called. ## DNS module -Use `require("dns")` to access this module. +Use `require('dns')` to access this module. -Here is an example which resolves `"www.google.com"` then reverse +Here is an example which resolves `'www.google.com'` then reverse resolves the IP addresses which are returned. - var dns = require("dns"), - sys = require("sys"); + var dns = require('dns'), + sys = require('sys'); - dns.resolve4("www.google.com", function (err, addresses) { + dns.resolve4('www.google.com', function (err, addresses) { if (err) throw err; - sys.puts("addresses: " + JSON.stringify(addresses)); + sys.puts('addresses: ' + JSON.stringify(addresses)); for (var i = 0; i < addresses.length; i++) { var a = addresses[i]; dns.reverse(a, function (err, domains) { if (err) { - puts("reverse for " + a + " failed: " + e.message); + puts('reverse for ' + a + ' failed: ' + e.message); } else { - sys.puts("reverse for " + a + ": " + JSON.stringify(domains)); + sys.puts('reverse for ' + a + ': ' + JSON.stringify(domains)); } }); } @@ -1899,7 +1987,7 @@ resolves the IP addresses which are returned. ### dns.resolve(domain, rrtype = 'A', callback) -Resolves a domain (e.g. `"google.com"`) into an array of the record types +Resolves a domain (e.g. `'google.com'`) into an array of the record types specified by rrtype. Valid rrtypes are `A` (IPV4 addresses), `AAAA` (IPV6 addresses), `MX` (mail exchange records), `TXT` (text records), `SRV` (SRV records), and `PTR` (used for reverse IP lookups). @@ -1916,7 +2004,7 @@ the error in English. ### dns.resolve4(domain, callback) The same as `dns.resolve()`, but only for IPv4 queries (`A` records). -`addresses` is an array of IPv4 addresses (e.g. `["74.125.79.104", "74.125.79.105", "74.125.79.106"]`). +`addresses` is an array of IPv4 addresses (e.g. `['74.125.79.104', '74.125.79.105', '74.125.79.106']`). ### dns.resolve6(domain, callback) @@ -1928,19 +2016,19 @@ The same as `dns.resolve4()` except for IPv6 queries (an `AAAA` query). The same as `dns.resolve()`, but only for mail exchange queries (`MX` records). `addresses` is an array of MX records, each with a priority and an exchange -attribute (e.g. `[{"priority": 10, "exchange": "mx.example.com"},...]`). +attribute (e.g. `[{'priority': 10, 'exchange': 'mx.example.com'},...]`). ### dns.resolveTxt(domain, callback) The same as `dns.resolve()`, but only for text queries (`TXT` records). `addresses` is an array of the text records available for `domain` (e.g., -`["v=spf1 ip4:0.0.0.0 ~all"]`). +`['v=spf1 ip4:0.0.0.0 ~all']`). ### dns.resolveSrv(domain, callback) The same as `dns.resolve()`, but only for service records (`SRV` records). `addresses` is an array of the SRV records available for `domain`. Properties -of SRV records are priority, weight, port, and name (e.g., `[{"priority": 10, {"weight": 5, "port": 21223, "name": "service.example.com"}, ...]`). +of SRV records are priority, weight, port, and name (e.g., `[{'priority': 10, {'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...]`). ### dns.reverse(ip, callback) @@ -1963,7 +2051,7 @@ Each DNS query can return an error code. ## Assert Module -This module is used for writing unit tests for your applications, you can access it with `require("assert")`. +This module is used for writing unit tests for your applications, you can access it with `require('assert')`. ### assert.fail(actual, expected, message, operator) @@ -2009,71 +2097,71 @@ Expects `block` not to throw an error. ## Path Module This module contains utilities for dealing with file paths. Use -`require("path")` to use it. It provides the following methods: +`require('path')` to use it. It provides the following methods: ### path.join(/* path1, path2, ... */) Join all arguments together and resolve the resulting path. Example: - node> require("path").join("/foo", "bar", "baz/asdf", "quux", "..") - "/foo/bar/baz/asdf" + node> require('path').join('/foo', 'bar', 'baz/asdf', 'quux', '..') + '/foo/bar/baz/asdf' ### path.normalizeArray(arr) -Normalize an array of path parts, taking care of `".."` and `"."` parts. Example: +Normalize an array of path parts, taking care of `'..'` and `'.'` parts. Example: - path.normalizeArray(["", - "foo", "bar", "baz", "asdf", "quux", ".."]) + path.normalizeArray(['', + 'foo', 'bar', 'baz', 'asdf', 'quux', '..']) // returns [ '', 'foo', 'bar', 'baz', 'asdf' ] ### path.normalize(p) -Normalize a string path, taking care of `".."` and `"."` parts. Example: +Normalize a string path, taking care of `'..'` and `'.'` parts. Example: - path.normalize("/foo/bar/baz/asdf/quux/..") + path.normalize('/foo/bar/baz/asdf/quux/..') // returns - "/foo/bar/baz/asdf" + '/foo/bar/baz/asdf' ### path.dirname(p) Return the directory name of a path. Similar to the Unix `dirname` command. Example: - path.dirname("/foo/bar/baz/asdf/quux") + path.dirname('/foo/bar/baz/asdf/quux') // returns - "/foo/bar/baz/asdf" + '/foo/bar/baz/asdf' ### path.basename(p, ext) Return the last portion of a path. Similar to the Unix `basename` command. Example: - path.basename("/foo/bar/baz/asdf/quux.html") + path.basename('/foo/bar/baz/asdf/quux.html') // returns - "quux.html" + 'quux.html' - path.basename("/foo/bar/baz/asdf/quux.html", ".html") + path.basename('/foo/bar/baz/asdf/quux.html', '.html') // returns - "quux" + 'quux' ### path.extname(p) Return the extension of the path. Everything after the last '.', if there is no '.' then it returns an empty string. Examples: - path.extname("index.html") + path.extname('index.html') // returns - ".html" + '.html' - path.extname("index") + path.extname('index') // returns - "" + '' ### path.exists(p, callback) Test whether or not the given path exists. Then, call the `callback` argument with either true or false. Example: - path.exists("/etc/passwd", function (exists) { - sys.debug(exists ? "it's there" : "no passwd!"); + path.exists('/etc/passwd', function (exists) { + sys.debug(exists ? 'it's there' : 'no passwd!'); }); @@ -2085,50 +2173,50 @@ Parsed URL objects have some or all of the following fields, depending on whether or not they exist in the URL string. Any parts that are not in the URL string will not be in the parsed object. Examples are shown for the URL -`"http://user:pass@host.com:8080/p/a/t/h?query=string#hash"` +`'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` - `href` The full URL that was originally parsed. Example: - `"http://user:pass@host.com:8080/p/a/t/h?query=string#hash"` + `'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` - `protocol` - The request protocol. Example: `"http:"` + The request protocol. Example: `'http:'` - `host` The full host portion of the URL, including port and authentication information. Example: - `"user:pass@host.com:8080"` + `'user:pass@host.com:8080'` - `auth` - The authentication information portion of a URL. Example: `"user:pass"` + The authentication information portion of a URL. Example: `'user:pass'` - `hostname` - Just the hostname portion of the host. Example: `"host.com"` + Just the hostname portion of the host. Example: `'host.com'` - `port` - The port number portion of the host. Example: `"8080"` + The port number portion of the host. Example: `'8080'` - `pathname` - The path section of the URL, that comes after the host and before the query, including the initial slash if present. Example: `"/p/a/t/h"` + The path section of the URL, that comes after the host and before the query, including the initial slash if present. Example: `'/p/a/t/h'` - `search` - The "query string" portion of the URL, including the leading question mark. Example: `"?query=string"` + The 'query string' portion of the URL, including the leading question mark. Example: `'?query=string'` - `query` - Either the "params" portion of the query string, or a querystring-parsed object. Example: - `"query=string"` or `{"query":"string"}` + Either the 'params' portion of the query string, or a querystring-parsed object. Example: + `'query=string'` or `{'query':'string'}` - `hash` - The "fragment" portion of the URL including the pound-sign. Example: `"#hash"` + The 'fragment' portion of the URL including the pound-sign. Example: `'#hash'` The following methods are provided by the URL module: @@ -2151,16 +2239,16 @@ Take a base URL, and a href URL, and resolve them as a browser would for an anch This module provides utilities for dealing with query strings. It provides the following methods: -### querystring.stringify(obj, sep="&", eq="=") +### querystring.stringify(obj, sep='&', eq='=') Serialize an object to a query string. Optionally override the default separator and assignment characters. Example: querystring.stringify({foo: 'bar'}) // returns - "foo=bar" + 'foo=bar' -### querystring.parse(str, sep="&", eq="=") +### querystring.parse(str, sep='&', eq='=') Deserialize a query string to an object. Optionally override the default separator and assignment characters. @@ -2187,7 +2275,7 @@ The standalone REPL is called `node-repl` and is installed at `$PREFIX/bin/node-repl`. It's recommended to use it with the program `rlwrap` for a better user interface. I set - alias node-repl="rlwrap node-repl" + alias node-repl='rlwrap node-repl' in my zsh configuration. @@ -2196,16 +2284,16 @@ result of the last expression. The library is called `/repl.js` and it can be used like this: - var sys = require("sys"), - net = require("net"), - repl = require("repl"); + var sys = require('sys'), + net = require('net'), + repl = require('repl'); nconnections = 0; net.createServer(function (c) { - sys.error("Connection!"); + sys.error('Connection!'); nconnections += 1; c.close(); }).listen(5000); - repl.start("simple tcp server> "); + repl.start('simple tcp server> '); The repl provides access to any variables in the global scope. You can expose a variable to the repl explicitly by assigning it to the `repl.scope` object: @@ -2248,7 +2336,7 @@ libraries. To get started let's make a small Addon which does the following except in C++: - exports.hello = "world"; + exports.hello = 'world'; To get started we create a file `hello.cc`: @@ -2256,7 +2344,7 @@ To get started we create a file `hello.cc`: using namespace v8; - extern "C" void + extern 'C' void init (Handle target) { HandleScope scope; @@ -2267,21 +2355,21 @@ This source code needs to be built into `hello.node`, the binary Addon. To do this we create a file called `wscript` which is python code and looks like this: - srcdir = "." - blddir = "build" - VERSION = "0.0.1" + srcdir = '.' + blddir = 'build' + VERSION = '0.0.1' def set_options(opt): - opt.tool_options("compiler_cxx") + opt.tool_options('compiler_cxx') def configure(conf): - conf.check_tool("compiler_cxx") - conf.check_tool("node_addon") + conf.check_tool('compiler_cxx') + conf.check_tool('node_addon') def build(bld): - obj = bld.new_task_gen("cxx", "shlib", "node_addon") - obj.target = "hello" - obj.source = "hello.cc" + obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') + obj.target = 'hello' + obj.source = 'hello.cc' Running `node-waf configure build` will create a file `build/default/hello.node` which is our Addon. @@ -2291,7 +2379,7 @@ provided for the ease of users. All Node addons must export a function called `init` with this signature: - extern "C" void init (Handle target) + extern 'C' void init (Handle target) For the moment, that is all the documentation on addons. Please see for a real example. diff --git a/doc/api_header.html b/doc/api_header.html index a133fd3aead..b25a908d2a2 100644 --- a/doc/api_header.html +++ b/doc/api_header.html @@ -4,29 +4,25 @@ node(1) -- evented I/O for V8 JavaScript + +
    -
    Table of Contents
    +
    Node.js v0.1.90
    From ee3026797c00e84ae13ab216da7f54835404e6a3 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 15:34:08 -0700 Subject: [PATCH 58/73] More documentation work. Remove long lines --- Makefile | 1 + doc/api.markdown | 103 ++++++++++++-------------------------------- doc/api_header.html | 20 +++------ 3 files changed, 34 insertions(+), 90 deletions(-) diff --git a/Makefile b/Makefile index 36a518d0827..b2c0cfc6236 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ benchmark: all # gem install ronn doc: doc/node.1 doc/api.html doc/index.html doc/changelog.html +## HACK to give the ronn-generated page a TOC doc/api.html: doc/api.markdown ronn -f --html doc/api.markdown \ | sed "s/

    \(.*\)<\/h2>/

    \1<\/h2>/g" \ diff --git a/doc/api.markdown b/doc/api.markdown index 3038d16c2a9..c59ac55a091 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -251,20 +251,20 @@ Closes the underlying file descriptor. Stream will not emit any more events. A **writable stream** has the following methods, members, and events. -### Event 'drain' +### Event: 'drain' `function () { }` Emitted after a `write()` method was called that returned `false` to indicate that it is safe to write again. -### Event 'error' +### Event: 'error' `function (exception) { }` Emitted on error with the exception `e`. -### Event 'close' +### Event: 'close' `function () { }` @@ -400,6 +400,7 @@ Example of listening for `SIGINT`: An easy way to send the `SIGINT` signal is with `Control-C` in most terminal programs. + ### process.stdout A writable stream to `stdout`. @@ -508,13 +509,6 @@ Returns the current working directory of the process. An object containing the user environment. See environ(7). - // print process.env - var sys = require('sys'); - - Object.getOwnPropertyNames(process.env).forEach(function (val, index, array) { - sys.puts(index + ': ' + val + '=' + process.env[val]); - }); - ### process.evalcx(code, sandbox, filename) @@ -741,45 +735,14 @@ Example of inspecting all properties of the `sys` object: To schedule execution of `callback` after `delay` milliseconds. Returns a `timeoutId` for possible use with `clearTimeout()`. - var sys = require('sys'), - start = new Date(), - timer = setTimeout(function () { - sys.puts('Timer fired after ' + (Date.now() - start) + 'ms'); - }, 1000); - - sys.puts('Started timer.'); - -Optionally, you can pass arguments to the callback. - - var sys = require('sys'), - start = new Date(), - timer = setTimeout(function (start_time, message) { - sys.puts(message + (Date.now() - start_time) + 'ms'); - }, 1000, start, 'Timer fired after '); - - sys.puts('Started timer.'); - -These two examples generate the same output. - ### clearTimeout(timeoutId) Prevents a timeout from triggering. - var sys = require('sys'), - start = new Date(), - timer1 = setTimeout(function () { - sys.puts('Timer fired after ' + (Date.now() - start) + 'ms'); - }, 5000), - timer2 = setTimeout(function () { - sys.puts('This is taking too long. Stopping timer1.'); - clearTimeout(timer1); - }, 1000); - - sys.puts('Started timers.'); - ### setInterval(callback, delay, [arg, ...]) -To schedule the repeated execution of `callback` every `delay` milliseconds. Returns a `intervalId` for possible use with `clearInterval()`. +To schedule the repeated execution of `callback` every `delay` milliseconds. +Returns a `intervalId` for possible use with `clearInterval()`. Optionally, you can also pass arguments to the callback. @@ -787,19 +750,6 @@ Optionally, you can also pass arguments to the callback. Stops a interval from triggering. - var sys = require('sys'), - start = new Date(), - count = 10, - timer = setInterval(function () { - count -= 1; - sys.puts('Timer fired after ' + (Date.now() - start) + 'ms ' + count + ' remaining.'); - if (count === 0) { - clearInterval(timer); - } - }, 100); - - sys.puts('Started timer.'); - ## Child Processes @@ -816,7 +766,7 @@ Child processes always have three streams associated with them. `child.stdin`, `ChildProcess` is an EventEmitter. -### Event 'exit' +### Event: 'exit' `function (code) {} ` @@ -1694,9 +1644,9 @@ chunked, this will send the terminating `'0\r\n\r\n'`. This object is created when making a request with `http.Client`. It is passed to the `'response'` event of the request object. -The response implements the stream interface. +The response implements the **readable stream** interface. -### Event 'data' +### Event: 'data' `function (chunk) {}` @@ -1829,24 +1779,25 @@ and passed to the user through the `'connection'` event of a server. `function () { }` -Call once the stream is established after a call to `createConnection()` or -`connect()`. +Emitted when a stream connection successfully is established. +See `connect()`. + ### Event: 'data' `function (data) { }` -Called when data is received on the stream. `data` -will be a string. Encoding of data is set by `stream.setEncoding()`. +Emitted when data is received. The argument `data` will be a `Buffer` or +`String`. Encoding of data is set by `stream.setEncoding()`. +(See the section on Readable Streams for more infromation.) ### Event: 'end' `function () { }` -Called when the other end of the stream sends a FIN -packet. After this is emitted the `readyState` will be -`'writeOnly'`. One should probably just call -`stream.end()` when this event is emitted. +Emitted when the other end of the stream sends a FIN packet. After this is +emitted the `readyState` will be `'writeOnly'`. One should probably just +call `stream.end()` when this event is emitted. ### Event: 'timeout' @@ -1874,7 +1825,7 @@ following this event. Emitted once the stream is fully closed. The argument `had_error` is a boolean which says if the stream was closed due to a transmission -error. +error. ### net.createConnection(port, host='127.0.0.1') @@ -1958,7 +1909,7 @@ algorithm, they buffer data before sending it off. Setting `noDelay` will immediately fire off data each time `stream.write()` is called. -## DNS module +## DNS Use `require('dns')` to access this module. @@ -2049,9 +2000,10 @@ Each DNS query can return an error code. - `dns.BADQUERY`: the query is malformed. -## Assert Module +## Assert -This module is used for writing unit tests for your applications, you can access it with `require('assert')`. +This module is used for writing unit tests for your applications, you can +access it with `require('assert')`. ### assert.fail(actual, expected, message, operator) @@ -2094,7 +2046,7 @@ Expects `block` to throw an error. Expects `block` not to throw an error. -## Path Module +## Path This module contains utilities for dealing with file paths. Use `require('path')` to use it. It provides the following methods: @@ -2165,9 +2117,10 @@ Test whether or not the given path exists. Then, call the `callback` argument w }); -## URL Module +## URL This module has utilities for URL resolution and parsing. +Call `require('url')` to use it. Parsed URL objects have some or all of the following fields, depending on whether or not they exist in the URL string. Any parts that are not in the URL @@ -2177,7 +2130,7 @@ string will not be in the parsed object. Examples are shown for the URL - `href` - The full URL that was originally parsed. Example: + The full URL that was originally parsed. Example: `'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` - `protocol` @@ -2235,7 +2188,7 @@ Take a parsed URL object, and return a formatted URL string. Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag. -## Query String Module +## Query String This module provides utilities for dealing with query strings. It provides the following methods: diff --git a/doc/api_header.html b/doc/api_header.html index b25a908d2a2..e3338bc95e3 100644 --- a/doc/api_header.html +++ b/doc/api_header.html @@ -11,7 +11,7 @@ line-height:1.3; color:#343331; background:#fff; } - #man { max-width:89ex; text-align:justify; margin:0 25px 25px 25px } + #man { max-width:89ex; text-align:justify; margin:0 25px 25px 10px } #man h1, #man h2, #man h3 { color:#232221;clear:left } #man h1 { font-size:28px; margin:15px 0 30px 0; text-align:center } #man h2 { font-size:18px; margin-bottom:0; margin-top:10px; line-height:1.3; } @@ -50,26 +50,18 @@ #man ol.man a:hover { color:#333231 } -body { - background:#fff; - color:#333; - font-family:helvetica; - font-size:14px; - line-height:1.3em; - padding:25px; -} - + #man { width: 50%; margin: 0 0 0 22em; } - + #toc { position: fixed; left: 0; top: 0; bottom: 0; - width: 20em; + width: 15em; border-right: 1px solid #ccc; overflow: auto; } @@ -84,8 +76,6 @@ body { } #toc ul li { margin: 0; - border: 1px solid #ccc; - border-width: 1px 0 0; } #toc ul li a { padding: 0.2em 0.4em; @@ -133,7 +123,7 @@ body {
    -
    Node.js v0.1.90
    +
    Node v0.1.90
    From 54f02345b5bd456900643456857c98fec0dc8e02 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 15:50:38 -0700 Subject: [PATCH 59/73] Fix doc again --- Makefile | 2 +- doc/api.markdown | 30 ++++++++++++++++++------------ doc/api_header.html | 9 ++++++++- doc/manpage.xsl | 28 ---------------------------- 4 files changed, 27 insertions(+), 42 deletions(-) delete mode 100644 doc/manpage.xsl diff --git a/Makefile b/Makefile index b2c0cfc6236..10de43a4fbc 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ benchmark: all doc: doc/node.1 doc/api.html doc/index.html doc/changelog.html ## HACK to give the ronn-generated page a TOC -doc/api.html: doc/api.markdown +doc/api.html: doc/api.markdown doc/api_header.html doc/api_footer.html ronn -f --html doc/api.markdown \ | sed "s/

    \(.*\)<\/h2>/

    \1<\/h2>/g" \ | cat doc/api_header.html - doc/api_footer.html > doc/api.html diff --git a/doc/api.markdown b/doc/api.markdown index c59ac55a091..a3ab8ad7b30 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -91,7 +91,7 @@ Use `process.mixin()` to include modules into the global namespace. puts('The area of a circle of radius 4 is ' + area(4)); -## String Encodings and Buffers +## Buffers Pure Javascript is Unicode friendly but not nice to pure binary data. When dealing with TCP streams or the file system, it's necessary to handle octet @@ -381,7 +381,7 @@ your program's flow. Especially for server programs that are designed to stay running forever, `uncaughtException` can be a useful safety mechanism. -### Signal Events: 'SIGINT' +### Signal Events `function () {}` @@ -849,7 +849,7 @@ Example: grep = spawn('grep', ['ssh']); sys.puts('Spawned child pid: ' + grep.pid); - grep.stdin.close(); + grep.stdin.end(); ### child.stdin.write(data, encoding) @@ -877,7 +877,7 @@ Example: A very elaborate way to run 'ps ax | grep ssh' if (code !== 0) { sys.puts('ps process exited with code ' + code); } - grep.stdin.close(); + grep.stdin.end(); }); grep.stdout.addListener('data', function (data) { @@ -895,7 +895,7 @@ Example: A very elaborate way to run 'ps ax | grep ssh' }); -### child.stdin.close() +### child.stdin.end() Closes the child process's `stdin` stream. This often causes the child process to terminate. @@ -909,7 +909,7 @@ Example: sys.puts('child process exited with code ' + code); }); - grep.stdin.close(); + grep.stdin.end(); ### child_process.exec(command, callback) @@ -1359,6 +1359,8 @@ Begin accepting connections on the specified port and hostname. If the hostname is omitted, the server will accept connections directed to any address. +To listen to a unix socket, supply a filename instead of port and hostname. + This function is asynchronous. `listening` will be emitted when the server is ready to accept connections. @@ -1698,7 +1700,7 @@ A reference to the `http.Client` that this response belongs to. ## net.Server -This class can be used to create a TCP or UNIX server. +This class is used to create a TCP or UNIX server. Here is an example of a echo server which listens for connections on port 7000: @@ -1719,6 +1721,11 @@ on port 7000: }); server.listen(7000, 'localhost'); +To listen on the socket `'/tmp/echo.sock'`, the last line would just be +changed to + + server.listen('/tmp/echo.sock'); + This is an EventEmitter with the following events: ### Event: 'listening' @@ -1737,11 +1744,10 @@ Emitted when a new connection is made. `stream` is an instance of ### Event: 'close' -`function (errno) {}` +`function () {}` + +Emitted when the server closes. -Emitted when the server closes. `errorno` is an integer which indicates -what, if any, error caused the server to close. If no error occurred -`errorno` will be 0. ### net.createServer(connectionListener) @@ -2244,7 +2250,7 @@ The library is called `/repl.js` and it can be used like this: net.createServer(function (c) { sys.error('Connection!'); nconnections += 1; - c.close(); + c.end(); }).listen(5000); repl.start('simple tcp server> '); diff --git a/doc/api_header.html b/doc/api_header.html index e3338bc95e3..498bc9ebd3a 100644 --- a/doc/api_header.html +++ b/doc/api_header.html @@ -53,10 +53,11 @@ #man { width: 50%; - margin: 0 0 0 22em; + margin: 0 0 0 17em; } #toc { + font-family:consolas,monospace; position: fixed; left: 0; top: 0; @@ -65,10 +66,16 @@ border-right: 1px solid #ccc; overflow: auto; } + #toc #toctitle { background: #eee; padding: 1em; } + +#toc a { + text-decoration: none; +} + #toc ul { list-style: none; margin: 0; diff --git a/doc/manpage.xsl b/doc/manpage.xsl deleted file mode 100644 index 6f7d3336ed5..00000000000 --- a/doc/manpage.xsl +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - From 07e64d45ffa1856e824c4fa6afd0442ba61d6fd8 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Apr 2010 16:58:29 -0700 Subject: [PATCH 60/73] bump version --- ChangeLog | 23 ++++++++++++++++++++++- doc/index.html | 4 ++-- wscript | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index c5dce40bb4d..9eef860976d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,25 @@ -2010.03.19, Version 0.1.33 +2010.04.09, Version 0.1.90 + + * Merge writing of networking system (net2) + - New Buffer object for binary data. + - Support UNIX sockets, Pipes + - Uniform stream API + - Currently no SSL + - Legacy modules can be accessed at 'http_old' and 'tcp_old' + + * Replace udns with c-ares. (Krishna Rajendran) + + * New documentation system using Markdown and Ronn + (Tim Caswell, Micheil Smith) + + * Better idle-time GC + + * Countless small bug fixes. + + * Upgrade V8 to 2.2.X, WAF 1.5.15 + + +2010.03.19, Version 0.1.33, 618296ef571e873976f608d91a3d6b9e65fe8284 * Include lib/ directory in node executable. Compile on demand. diff --git a/doc/index.html b/doc/index.html index e49f55ae2a9..e9c96c94935 100644 --- a/doc/index.html +++ b/doc/index.html @@ -95,8 +95,8 @@ server.listen(7000, "localhost"); git repo

    - 2010.03.19 - node-v0.1.33.tar.gz + 2010.04.09 + node-v0.1.90.tar.gz

    Build

    diff --git a/wscript b/wscript index fb8f77907d1..cfe78a80416 100644 --- a/wscript +++ b/wscript @@ -7,7 +7,7 @@ from os.path import join, dirname, abspath from logging import fatal cwd = os.getcwd() -VERSION="0.1.33" +VERSION="0.1.90" APPNAME="node.js" import js2c From dd50b864497dfa2854f12d10f175900e071e2b63 Mon Sep 17 00:00:00 2001 From: James Herdman Date: Sat, 10 Apr 2010 12:08:11 -0400 Subject: [PATCH 61/73] Fix documentation errors for DNS --- doc/api.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api.markdown b/doc/api.markdown index a3ab8ad7b30..a9c3e069540 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1934,7 +1934,7 @@ resolves the IP addresses which are returned. var a = addresses[i]; dns.reverse(a, function (err, domains) { if (err) { - puts('reverse for ' + a + ' failed: ' + e.message); + sys.puts('reverse for ' + a + ' failed: ' + err.message); } else { sys.puts('reverse for ' + a + ': ' + JSON.stringify(domains)); } From 93913dbdb8f621bef46c61d1f8a824a19a57dfa5 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 11 Apr 2010 12:21:33 -0700 Subject: [PATCH 62/73] Add failing test for HEAD requests Needs to be fixed for 0.2. --- test/simple/test-http-head-request.js | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/simple/test-http-head-request.js diff --git a/test/simple/test-http-head-request.js b/test/simple/test-http-head-request.js new file mode 100644 index 00000000000..671e3ae83bf --- /dev/null +++ b/test/simple/test-http-head-request.js @@ -0,0 +1,39 @@ +require('../common'); + +var assert = require("assert"); +var http = require("http"); +var sys = require("sys"); + +var body = "hello world"; + +server = http.createServer(function (req, res) { + res.writeHeader(200 , { 'Content-Length': body.length.toString() + , 'Content-Type': 'text/plain' + }); + sys.puts('method: ' + req.method); + if (req.method != 'HEAD') res.write(body); + res.end(); +}); +server.listen(PORT); + +var gotEnd = false; + +server.addListener('listening', function() { + var client = http.createClient(PORT); + var request = client.request("HEAD", "/"); + request.addListener('response', function (response) { + sys.puts('got response'); + response.addListener("data", function () { + process.exit(2); + }); + response.addListener("end", function () { + process.exit(0); + }); + }); + request.end(); +}); + +//give a bit of time for the server to respond before we check it +setTimeout(function() { + process.exit(1); +}, 2000); From 57fbb627cadb356bc335274d203c21c71d022b5d Mon Sep 17 00:00:00 2001 From: isaacs Date: Sun, 11 Apr 2010 13:46:24 -0700 Subject: [PATCH 63/73] trailing whitespace fixes --- lib/assert.js | 2 +- lib/fs.js | 4 +-- lib/http_old.js | 10 ++++---- lib/net.js | 4 +-- lib/querystring.js | 16 ++++++------ lib/repl.js | 28 ++++++++++----------- lib/sys.js | 4 +-- lib/url.js | 62 +++++++++++++++++++++++----------------------- 8 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index 6dc06213cc2..da9198a8d80 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -112,7 +112,7 @@ assert.equal = function equal(actual, expected, message) { // with != assert.notEqual(actual, expected, message_opt); assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { + if (actual == expected) { fail(actual, expected, message, "!=", assert.notEqual); } }; diff --git a/lib/fs.js b/lib/fs.js index 2157bc1b444..4b2a4d120ad 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -98,7 +98,7 @@ function stringToFlags(flag) { case "r+": return process.O_RDWR; case "w": return process.O_CREAT | process.O_TRUNC | process.O_WRONLY; case "w+": return process.O_CREAT | process.O_TRUNC | process.O_RDWR; - case "a": return process.O_APPEND | process.O_CREAT | process.O_WRONLY; + case "a": return process.O_APPEND | process.O_CREAT | process.O_WRONLY; case "a+": return process.O_APPEND | process.O_CREAT | process.O_RDWR; default: throw new Error("Unknown file open flag: " + flag); } @@ -707,7 +707,7 @@ var writeStreamCloseWarning; FileWriteStream.prototype.close = function (cb) { if (!writeStreamCloseWarning) { writeStreamCloseWarning = "FileWriteStream.prototype.close renamed to end()"; - sys.error(writeStreamCloseWarning); + sys.error(writeStreamCloseWarning); } return this.end(cb); } diff --git a/lib/http_old.js b/lib/http_old.js index 832df6b2cb2..061c0dd8fd7 100644 --- a/lib/http_old.js +++ b/lib/http_old.js @@ -215,7 +215,7 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, headers) { OutgoingMessage.prototype.sendBody = function () { - throw new Error("sendBody() has been renamed to write(). " + + throw new Error("sendBody() has been renamed to write(). " + "The 'body' event has been renamed to 'data' and " + "the 'complete' event has been renamed to 'end'."); }; @@ -338,7 +338,7 @@ function createIncomingMessageStream (connection, incoming_listener) { field = null; value = null; }); - + // Only servers will get URL events. connection.addListener("url", function (data) { incoming.url += data; @@ -580,7 +580,7 @@ http.Client.prototype.request = function (method, url, headers) { exports.cat = function (url, encoding_, headers_) { - var encoding = 'utf8', + var encoding = 'utf8', headers = {}, callback = null; @@ -604,7 +604,7 @@ exports.cat = function (url, encoding_, headers_) { } var url = require("url").parse(url); - + var hasHost = false; for (var i in headers) { if (i.toLowerCase() === "host") { @@ -615,7 +615,7 @@ exports.cat = function (url, encoding_, headers_) { if (!hasHost) headers["Host"] = url.hostname; var content = ""; - + var client = exports.createClient(url.port || 80, url.hostname); var req = client.request((url.pathname || "/")+(url.search || "")+(url.hash || ""), headers); diff --git a/lib/net.js b/lib/net.js index 07e34d3fce9..28de43595f4 100644 --- a/lib/net.js +++ b/lib/net.js @@ -340,7 +340,7 @@ function initStream (self) { self.readable = false; // Queue of buffers and string that need to be written to socket. - self._writeQueue = []; + self._writeQueue = []; self._writeQueueEncoding = []; self._writeWatcher = ioWatchers.alloc(); @@ -608,7 +608,7 @@ Stream.prototype.connect = function () { initStream(self); if (self.fd) throw new Error('Stream already opened'); if (!self._readWatcher) throw new Error('No readWatcher'); - + timeout.active(socket); var port = parseInt(arguments[0]); diff --git a/lib/querystring.js b/lib/querystring.js index ef50cafa45d..5220b53ae99 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -30,7 +30,7 @@ QueryString.stringify = function (obj, sep, eq, name) { if (isA(obj, null) || isA(obj, undefined) || typeof(obj) === 'function') { return name ? encodeURIComponent(name) + eq : ''; } - + if (isBool(obj)) obj = +obj; if (isNumber(obj) || isString(obj)) { return encodeURIComponent(name) + eq + encodeURIComponent(obj); @@ -44,14 +44,14 @@ QueryString.stringify = function (obj, sep, eq, name) { return s.join(sep); } // now we know it's an object. - + // Check for cyclical references in nested objects for (var i = stack.length - 1; i >= 0; --i) if (stack[i] === obj) { throw new Error("querystring.stringify. Cyclical reference"); } - + stack.push(obj); - + var s = []; var begin = name ? name + '[' : ''; var end = name ? ']' : ''; @@ -59,9 +59,9 @@ QueryString.stringify = function (obj, sep, eq, name) { var n = begin + i + end; s.push(QueryString.stringify(obj[i], sep, eq, n)); } - + stack.pop(); - + s = s.join(sep); if (!s && name) return name + "="; return s; @@ -112,10 +112,10 @@ var pieceParser = function (eq) { } // ["foo[][bar][][baz]", "foo[][bar][]", "baz"] var tail = sliced[2], head = sliced[1]; - + // array: key[]=val if (!tail) return parsePiece(head, [val]); - + // obj: key[subkey]=val var ret = {}; ret[tail] = val; diff --git a/lib/repl.js b/lib/repl.js index 28bf15817cf..6188d7a3b3c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -32,13 +32,13 @@ exports.start = function (prompt) { */ function readline (cmd) { cmd = trimWhitespace(cmd); - + // Check to see if a REPL keyword was used. If it returns true, // display next prompt and return. if (parseREPLKeyword(cmd) === true) { return; } - + // The catchall for errors try { buffered_cmd += "\n" + cmd; @@ -46,7 +46,7 @@ function readline (cmd) { // continue onto the next line. try { buffered_cmd = convertToScope(buffered_cmd); - + // Scope the readline with exports.scope to provide "local" vars with (exports.scope) { var ret = eval(buffered_cmd); @@ -55,7 +55,7 @@ function readline (cmd) { exports.writer(ret); } } - + buffered_cmd = ''; } catch (e) { if (!(e instanceof SyntaxError)) throw e; @@ -69,13 +69,13 @@ function readline (cmd) { } buffered_cmd = ''; } - + displayPrompt(); } /** - * Used to display the prompt. + * Used to display the prompt. */ function displayPrompt () { sys.print(buffered_cmd.length ? '... ' : exports.prompt); @@ -83,9 +83,9 @@ function displayPrompt () { /** * Used to parse and execute the Node REPL commands. - * + * * @param {cmd} cmd The command entered to check - * @returns {Boolean} If true it means don't continue parsing the command + * @returns {Boolean} If true it means don't continue parsing the command */ function parseREPLKeyword (cmd) { switch (cmd) { @@ -115,9 +115,9 @@ function parseREPLKeyword (cmd) { /** * Trims Whitespace from a line. - * + * * @param {String} cmd The string to trim the whitespace from - * @returns {String} The trimmed string + * @returns {String} The trimmed string */ function trimWhitespace (cmd) { var matches = trimmer.exec(cmd); @@ -130,24 +130,24 @@ function trimWhitespace (cmd) { * Converts commands that use var and function () to use the * local exports.scope when evaled. This provides a local scope * on the REPL. - * + * * @param {String} cmd The cmd to convert * @returns {String} The converted command */ function convertToScope (cmd) { var matches; - + // Replaces: var foo = "bar"; with: exports.scope.foo = bar; matches = scopedVar.exec(cmd); if (matches && matches.length == 3) { return "exports.scope." + matches[1] + matches[2]; } - + // Replaces: function foo() {}; with: foo = function foo() {}; matches = scopeFunc.exec(buffered_cmd); if (matches && matches.length == 2) { return matches[1] + " = " + buffered_cmd; } - + return cmd; } diff --git a/lib/sys.js b/lib/sys.js index d4e601450b1..7bf582d88da 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -83,7 +83,7 @@ exports.inspect = function (obj, showHidden, depth) { } else { base = ""; } - + // Make dates with properties first say the date if (value instanceof Date) { base = ' ' + value.toUTCString(); @@ -160,7 +160,7 @@ exports.inspect = function (obj, showHidden, depth) { return name + ": " + str; }); - + var numLinesEst = 0; var length = output.reduce(function(prev, cur) { numLinesEst++; diff --git a/lib/url.js b/lib/url.js index ce2a5508e04..e6f2d71ebe5 100644 --- a/lib/url.js +++ b/lib/url.js @@ -20,17 +20,17 @@ var protocolPattern = /^([a-z0-9]+:)/, function urlParse (url, parseQueryString) { if (url && typeof(url) === "object" && url.href) return url; - + var out = { href : url }, rest = url; - + var proto = protocolPattern.exec(rest); if (proto) { proto = proto[0]; out.protocol = proto; rest = rest.substr(proto.length); } - + // figure out if it's got a host var slashes = rest.substr(0, 2) === "//"; if (slashes && !(proto && hostlessProtocol[proto])) { @@ -48,19 +48,19 @@ function urlParse (url, parseQueryString) { } if (firstNonHost !== -1) { out.host = rest.substr(0, firstNonHost); - rest = rest.substr(firstNonHost); + rest = rest.substr(firstNonHost); } else { out.host = rest; rest = ""; } - + // pull out the auth and port. var p = parseHost(out.host); for (var i in p) out[i] = p[i]; // we've indicated that there is a hostname, so even if it's empty, it has to be present. out.hostname = out.hostname || ""; } - + // now rest is set to the post-host stuff. // chop off from the tail first. var hash = rest.indexOf("#"); @@ -79,7 +79,7 @@ function urlParse (url, parseQueryString) { rest = rest.slice(0, qm); } if (rest) out.pathname = rest; - + return out; }; @@ -88,37 +88,37 @@ function urlFormat (obj) { // ensure it's an object, and not a string url. If it's an obj, this is a no-op. // this way, you can call url_format() on strings to clean up potentially wonky urls. if (typeof(obj) === "string") obj = urlParse(obj); - + var protocol = obj.protocol || "", host = (obj.host !== undefined) ? obj.host : obj.hostname !== undefined ? ( (obj.auth ? obj.auth + "@" : "") + obj.hostname + (obj.port ? ":" + obj.port : "") - ) + ) : false, pathname = obj.pathname || "", search = obj.search || ( obj.query && ( "?" + ( - typeof(obj.query) === "object" + typeof(obj.query) === "object" ? querystring.stringify(obj.query) : String(obj.query) )) ) || "", hash = obj.hash || ""; - + if (protocol && protocol.substr(-1) !== ":") protocol += ":"; - + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. if (obj.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) { host = "//" + (host || ""); if (pathname && pathname.charAt(0) !== "/") pathname = "/" + pathname; } else if (!host) host = ""; - + if (hash && hash.charAt(0) !== "#") hash = "#" + hash; if (search && search.charAt(0) !== "?") search = "?" + search; - + return protocol + host + pathname + search + hash; }; @@ -128,30 +128,30 @@ function urlResolve (source, relative) { function urlResolveObject (source, relative) { if (!source) return relative; - + source = urlParse(urlFormat(source)); relative = urlParse(urlFormat(relative)); // hash is always overridden, no matter what. source.hash = relative.hash; - + if (relative.href === "") return source; - + // hrefs like //foo/bar always cut to the protocol. if (relative.slashes && !relative.protocol) { relative.protocol = source.protocol; return relative; } - + if (relative.protocol && relative.protocol !== source.protocol) { // if it's a known url protocol, then changing the protocol does weird things // first, if it's not file:, then we MUST have a host, and if there was a path // to begin with, then we MUST have a path. // if it is file:, then the host is dropped, because that's known to be hostless. // anything else is assumed to be absolute. - + if (!slashedProtocol[relative.protocol]) return relative; - + source.protocol = relative.protocol; if (!relative.host && !hostlessProtocol[relative.protocol]) { var relPath = (relative.pathname || "").split("/"); @@ -181,13 +181,13 @@ function urlResolveObject (source, relative) { srcPath = source.pathname && source.pathname.split("/") || [], relPath = relative.pathname && relative.pathname.split("/") || [], psychotic = source.protocol && !slashedProtocol[source.protocol] && source.host !== undefined; - + // if the url is a non-slashed url, then relative links like ../.. should be able // to crawl up to the hostname, as well. This is strange. // source.protocol has already been set by now. // Later on, put the first path part into the host field. if ( psychotic ) { - + delete source.hostname; delete source.auth; delete source.port; @@ -196,7 +196,7 @@ function urlResolveObject (source, relative) { else srcPath.unshift(source.host); } delete source.host; - + if (relative.protocol) { delete relative.hostname; delete relative.auth; @@ -209,7 +209,7 @@ function urlResolveObject (source, relative) { } mustEndAbs = mustEndAbs && (relPath[0] === "" || srcPath[0] === ""); } - + if (isRelAbs) { // it's absolute. source.host = (relative.host || relative.host === "") ? relative.host : source.host; @@ -242,7 +242,7 @@ function urlResolveObject (source, relative) { delete source.pathname; return source; } - + // resolve dots. // if a url ENDs in . or .., then it must get a trailing slash. // however, if it ends in anything else non-slashy, then it must NOT get a trailing slash. @@ -251,7 +251,7 @@ function urlResolveObject (source, relative) { (source.host || relative.host) && (last === "." || last === "..") || last === "" ); - + // Figure out if this has to end up as an absolute url, or should continue to be relative. srcPath = path.normalizeArray(srcPath, true); if (srcPath.length === 1 && srcPath[0] === ".") srcPath = []; @@ -262,23 +262,23 @@ function urlResolveObject (source, relative) { if (dir === "..") dirs.pop(); else if (dir !== ".") dirs.push(dir); }); - + if (mustEndAbs && dirs[0] !== "") { dirs.unshift(""); } srcPath = dirs; } if (hasTrailingSlash && (srcPath.length < 2 || srcPath.slice(-1)[0] !== "")) srcPath.push(""); - + // put the host back if ( psychotic ) source.host = srcPath[0] === "" ? "" : srcPath.shift(); - + mustEndAbs = mustEndAbs || (source.host && srcPath.length); - + if (mustEndAbs && srcPath[0] !== "") srcPath.unshift("") source.pathname = srcPath.join("/"); - + return source; }; From 8553e8a15d0ff3715fb3a8a02062de9dcb9339b6 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 11 Apr 2010 15:15:36 -0700 Subject: [PATCH 64/73] Add incoming.httpVersion --- doc/api.markdown | 6 +++++- lib/http.js | 3 +++ test/simple/test-http-1.0.js | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/api.markdown b/doc/api.markdown index a9c3e069540..525743c3a4a 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1448,7 +1448,9 @@ Read only. ### request.httpVersion The HTTP protocol version as a string. Read only. Examples: -`'1.1'`, `'1.0'` +`'1.1'`, `'1.0'`. +Also `request.httpVersionMajor` is the first integer and +`request.httpVersionMinor` is the second. ### request.setEncoding(encoding='binary') @@ -1674,6 +1676,8 @@ The 3-digit HTTP response status code. E.G. `404`. The HTTP version of the connected-to server. Probably either `'1.1'` or `'1.0'`. +Also `response.httpVersionMajor` is the first integer and +`response.httpVersionMinor` is the second. ### response.headers diff --git a/lib/http.js b/lib/http.js index da6cb384d91..12130b68b66 100644 --- a/lib/http.js +++ b/lib/http.js @@ -70,6 +70,9 @@ function newParser (type) { parser.incoming.httpVersionMajor = info.versionMajor; parser.incoming.httpVersionMinor = info.versionMinor; + parser.incoming.httpVersion = info.versionMajor + + '.' + + info.versionMinor ; if (info.method) { // server only diff --git a/test/simple/test-http-1.0.js b/test/simple/test-http-1.0.js index 248c7fc5021..534a4082361 100644 --- a/test/simple/test-http-1.0.js +++ b/test/simple/test-http-1.0.js @@ -7,6 +7,9 @@ var server_response = ""; var client_got_eof = false; var server = http.createServer(function (req, res) { + assert.equal('1.0', req.httpVersion); + assert.equal(1, req.httpVersionMajor); + assert.equal(0, req.httpVersionMinor); res.writeHead(200, {"Content-Type": "text/plain"}); res.end(body); }) From 715e119eea035930fc8e550cf982f6efb47580b3 Mon Sep 17 00:00:00 2001 From: Matt Ranney Date: Tue, 23 Mar 2010 23:27:31 -0700 Subject: [PATCH 65/73] Fix typo in comments. --- lib/net.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/net.js b/lib/net.js index 28de43595f4..f3461c5b6e0 100644 --- a/lib/net.js +++ b/lib/net.js @@ -778,7 +778,7 @@ function Server (listener) { self.emit('connection', s); // The 'connect' event probably should be removed for server-side - // sockets. It's redundent. + // sockets. It's redundant. s.emit('connect'); } }; From cc9d5ab546e92ff9e56e4355e0cf0e557221bbab Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 11 Apr 2010 16:12:20 -0700 Subject: [PATCH 66/73] C-Ares shouldn't iterate over all Object.prototype elements and furthermore error out of one of them isn't a DNS option. Test case by Ben Lund ; additional help from Tim Caswell . --- src/node_cares.cc | 21 ++++++------------- .../test-regression-object-prototype.js | 8 +++++++ 2 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 test/simple/test-regression-object-prototype.js diff --git a/src/node_cares.cc b/src/node_cares.cc index 82d2a64b939..076540d8f73 100644 --- a/src/node_cares.cc +++ b/src/node_cares.cc @@ -422,22 +422,13 @@ Handle Channel::New(const Arguments& args) { } Local options_o = Local::Cast(args[0]); - Local keys = options_o->GetPropertyNames(); - int length = keys->Length(); - for (int i = 0; i < length; ++i) { - Local opt = Local::Cast(keys->Get(Integer::New(i))); - - if (opt->Equals(String::New("SOCK_STATE_CB"))) { - c->handle_->Set(callback_symbol, options_o->Get(opt)); - options.sock_state_cb_data = c; - options.sock_state_cb = Channel::SockStateCb; - optmask |= ARES_OPT_SOCK_STATE_CB; - continue; - } - - return ThrowException(Exception::Error( - String::New("Unknown Option"))); + Local cb = options_o->Get(String::NewSymbol("SOCK_STATE_CB")); + if (!cb.IsEmpty()) { + c->handle_->Set(callback_symbol, cb); + options.sock_state_cb_data = c; + options.sock_state_cb = Channel::SockStateCb; + optmask |= ARES_OPT_SOCK_STATE_CB; } } diff --git a/test/simple/test-regression-object-prototype.js b/test/simple/test-regression-object-prototype.js new file mode 100644 index 00000000000..7c6f45138f7 --- /dev/null +++ b/test/simple/test-regression-object-prototype.js @@ -0,0 +1,8 @@ +var sys = require('sys'); + +//sys.puts('puts before'); + +Object.prototype.xadsadsdasasdxx = function () { +}; + +sys.puts('puts after'); From b7441040f87ff5e0e7b4575852996b6a64e0ea8f Mon Sep 17 00:00:00 2001 From: Matt Ranney Date: Sun, 11 Apr 2010 16:13:32 -0700 Subject: [PATCH 67/73] REPL can be run from multiple different streams. e.g. from UNIX sockets with socat. --- lib/repl.js | 191 +++++++++++++++++++++------------------ test/simple/test-repl.js | 138 ++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 88 deletions(-) create mode 100644 test/simple/test-repl.js diff --git a/lib/repl.js b/lib/repl.js index 6188d7a3b3c..a092e470484 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1,153 +1,168 @@ // A repl library that you can include in your own code to get a runtime -// interface to your program. Just require("/repl.js"). +// interface to your program. +// +// var repl = require("/repl.js"); +// repl.start("prompt> "); // start repl on stdin +// net.createServer(function (socket) { // listen for unix socket connections and start repl on them +// repl.start("node via Unix socket> ", socket); +// }).listen("/tmp/node-repl-sock"); +// net.createServer(function (socket) { // listen for TCP socket connections and start repl on them +// repl.start("node via TCP socket> ", socket); +// }).listen(5001); + +// repl.start("node > ").scope.foo = "stdin is fun"; // expose foo to repl scope var sys = require('sys'); -var buffered_cmd = ''; -var trimmer = /^\s*(.+)\s*$/m; -var scopedVar = /^\s*var\s*([_\w\$]+)(.*)$/m; -var scopeFunc = /^\s*function\s*([_\w\$]+)/; - -exports.scope = {}; -exports.prompt = "node> "; // Can overridden with custom print functions, such as `probe` or `eyes.js` -exports.writer = sys.p; +exports.writer = sys.inspect; -var stdin; - -exports.start = function (prompt) { - if (prompt !== undefined) { - exports.prompt = prompt; - } - - stdin = process.openStdin(); - stdin.setEncoding('utf8'); - stdin.addListener("data", readline); - displayPrompt(); +function REPLServer(prompt, stream) { + var self = this; + + self.scope = {}; + self.buffered_cmd = ''; + self.prompt = prompt || "node> "; + self.stream = stream || process.openStdin(); + self.stream.setEncoding('utf8'); + self.stream.addListener("data", function (chunk) { + self.readline.call(self, chunk); + }); + self.displayPrompt(); } +exports.REPLServer = REPLServer; -/** - * The main REPL function. This is called everytime the user enters - * data on the command line. - */ -function readline (cmd) { - cmd = trimWhitespace(cmd); +// prompt is a string to print on each line for the prompt, +// source is a stream to use for I/O, defaulting to stdin/stdout. +exports.start = function (prompt, source) { + return new REPLServer(prompt, source); +}; +REPLServer.prototype.displayPrompt = function () { + var self = this; + self.stream.write(self.buffered_cmd.length ? '... ' : self.prompt); +}; + +// read a line from the stream, then eval it +REPLServer.prototype.readline = function (cmd) { + var self = this; + + cmd = self.trimWhitespace(cmd); + // Check to see if a REPL keyword was used. If it returns true, // display next prompt and return. - if (parseREPLKeyword(cmd) === true) { + if (self.parseREPLKeyword(cmd) === true) { return; } - + // The catchall for errors try { - buffered_cmd += "\n" + cmd; + self.buffered_cmd += cmd; // This try is for determining if the command is complete, or should // continue onto the next line. try { - buffered_cmd = convertToScope(buffered_cmd); - - // Scope the readline with exports.scope to provide "local" vars - with (exports.scope) { - var ret = eval(buffered_cmd); + self.buffered_cmd = self.convertToScope(self.buffered_cmd); + + // Scope the readline with self.scope to provide "local" vars and make Douglas Crockford cry + with (self.scope) { + var ret = eval(self.buffered_cmd); if (ret !== undefined) { - exports.scope['_'] = ret; - exports.writer(ret); + self.scope['_'] = ret; + self.stream.write(exports.writer(ret) + "\n"); } } - - buffered_cmd = ''; + + self.buffered_cmd = ''; } catch (e) { if (!(e instanceof SyntaxError)) throw e; } } catch (e) { // On error: Print the error and clear the buffer if (e.stack) { - sys.puts(e.stack); + self.stream.write(e.stack + "\n"); } else { - sys.puts(e.toString()); + self.stream.write(e.toString() + "\n"); } - buffered_cmd = ''; + self.buffered_cmd = ''; } - - displayPrompt(); -} - - -/** - * Used to display the prompt. - */ -function displayPrompt () { - sys.print(buffered_cmd.length ? '... ' : exports.prompt); -} + + self.displayPrompt(); +}; /** * Used to parse and execute the Node REPL commands. - * + * * @param {cmd} cmd The command entered to check - * @returns {Boolean} If true it means don't continue parsing the command + * @returns {Boolean} If true it means don't continue parsing the command */ -function parseREPLKeyword (cmd) { + +REPLServer.prototype.parseREPLKeyword = function (cmd) { + var self = this; + switch (cmd) { case ".break": - buffered_cmd = ''; - displayPrompt(); + self.buffered_cmd = ''; + self.displayPrompt(); return true; case ".clear": - sys.puts("Clearing Scope..."); - buffered_cmd = ''; - exports.scope = {}; - displayPrompt(); + self.stream.write("Clearing Scope...\n"); + self.buffered_cmd = ''; + self.scope = {}; + self.displayPrompt(); return true; case ".exit": - stdin.close(); + self.stream.close(); return true; case ".help": - sys.puts(".break\tSometimes you get stuck in a place you can't get out... This will get you out."); - sys.puts(".clear\tBreak, and also clear the local scope."); - sys.puts(".exit\tExit the prompt"); - sys.puts(".help\tShow repl options"); - displayPrompt(); + self.stream.write(".break\tSometimes you get stuck in a place you can't get out... This will get you out.\n"); + self.stream.write(".clear\tBreak, and also clear the local scope.\n"); + self.stream.write(".exit\tExit the prompt\n"); + self.stream.write(".help\tShow repl options\n"); + self.displayPrompt(); return true; } return false; -} +}; /** * Trims Whitespace from a line. - * + * * @param {String} cmd The string to trim the whitespace from - * @returns {String} The trimmed string + * @returns {String} The trimmed string */ -function trimWhitespace (cmd) { - var matches = trimmer.exec(cmd); - if (matches && matches.length == 2) { +REPLServer.prototype.trimWhitespace = function (cmd) { + var trimmer = /^\s*(.+)\s*$/m, + matches = trimmer.exec(cmd); + + if (matches && matches.length === 2) { return matches[1]; } -} +}; /** * Converts commands that use var and function () to use the * local exports.scope when evaled. This provides a local scope * on the REPL. - * + * * @param {String} cmd The cmd to convert * @returns {String} The converted command */ -function convertToScope (cmd) { - var matches; - - // Replaces: var foo = "bar"; with: exports.scope.foo = bar; - matches = scopedVar.exec(cmd); - if (matches && matches.length == 3) { - return "exports.scope." + matches[1] + matches[2]; +REPLServer.prototype.convertToScope = function (cmd) { + var self = this, matches, + scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m, + scopeFunc = /^\s*function\s*([_\w\$]+)/; + + // Replaces: var foo = "bar"; with: self.scope.foo = bar; + matches = scopeVar.exec(cmd); + if (matches && matches.length === 3) { + return "self.scope." + matches[1] + matches[2]; } - + // Replaces: function foo() {}; with: foo = function foo() {}; - matches = scopeFunc.exec(buffered_cmd); - if (matches && matches.length == 2) { - return matches[1] + " = " + buffered_cmd; + matches = scopeFunc.exec(self.buffered_cmd); + if (matches && matches.length === 2) { + return matches[1] + " = " + self.buffered_cmd; } - + return cmd; -} +}; diff --git a/test/simple/test-repl.js b/test/simple/test-repl.js new file mode 100644 index 00000000000..54511ce3dfd --- /dev/null +++ b/test/simple/test-repl.js @@ -0,0 +1,138 @@ +require("../common"); +var sys = require("sys"), + net = require("net"), + repl = require("repl"), + message = "Read, Eval, Print Loop", + unix_socket_path = "/tmp/node-repl-sock", + prompt_unix = "node via Unix socket> ", + prompt_tcp = "node via TCP socket> ", + server_tcp, server_unix, client_tcp, client_unix, timer; + +debug('repl test'); + +// function for REPL to run +invoke_me = function (arg) { + return "invoked " + arg; +}; + +function send_expect(list) { + if (list.length > 0) { + var cur = list.shift(); + + cur.client.expect = cur.expect; + cur.client.list = list; + if (cur.send.length > 0) { + cur.client.write(cur.send); + } + } +} + +function tcp_test() { + server_tcp = net.createServer(function (socket) { + assert.strictEqual(server_tcp, socket.server); + assert.strictEqual(server_tcp.type, 'tcp4'); + + socket.addListener("end", function () { + socket.end(); + }); + + repl.start(prompt_tcp, socket); + }); + + server_tcp.addListener('listening', function () { + client_tcp = net.createConnection(PORT); + + client_tcp.addListener('connect', function () { + assert.equal(true, client_tcp.readable); + assert.equal(true, client_tcp.writable); + + send_expect([ + { client: client_tcp, send: "", expect: prompt_tcp }, + { client: client_tcp, send: "invoke_me(333)", expect: ('\'' + "invoked 333" + '\'\n' + prompt_tcp) }, + { client: client_tcp, send: "a += 1", expect: ("12346" + '\n' + prompt_tcp) } + ]); + }); + + client_tcp.addListener('data', function (data) { + var data_str = data.asciiSlice(0, data.length); + sys.puts("TCP data: " + data_str + ", compare to " + client_tcp.expect); + assert.strictEqual(client_tcp.expect, data_str); + if (client_tcp.list && client_tcp.list.length > 0) { + send_expect(client_tcp.list); + } + else { + sys.puts("End of TCP test."); + client_tcp.end(); + client_unix.end(); + clearTimeout(timer); + } + }); + + client_tcp.addListener("error", function (e) { + throw e; + }); + + client_tcp.addListener("close", function () { + server_tcp.close(); + }); + }); + + server_tcp.listen(PORT); +} + +function unix_test() { + server_unix = net.createServer(function (socket) { + assert.strictEqual(server_unix, socket.server); + assert.strictEqual(server_unix.type, 'unix'); + + socket.addListener("end", function () { + socket.end(); + }); + + repl.start(prompt_unix, socket).scope.message = message; + }); + + server_unix.addListener('listening', function () { + client_unix = net.createConnection(unix_socket_path); + + client_unix.addListener('connect', function () { + assert.equal(true, client_unix.readable); + assert.equal(true, client_unix.writable); + + send_expect([ + { client: client_unix, send: "", expect: prompt_unix }, + { client: client_unix, send: "message", expect: ('\'' + message + '\'\n' + prompt_unix) }, + { client: client_unix, send: "invoke_me(987)", expect: ('\'' + "invoked 987" + '\'\n' + prompt_unix) }, + { client: client_unix, send: "a = 12345", expect: ("12345" + '\n' + prompt_unix) } + ]); + }); + + client_unix.addListener('data', function (data) { + var data_str = data.asciiSlice(0, data.length); + sys.puts("Unix data: " + data_str + ", compare to " + client_unix.expect); + assert.strictEqual(client_unix.expect, data_str); + if (client_unix.list && client_unix.list.length > 0) { + send_expect(client_unix.list); + } + else { + sys.puts("End of Unix test, running TCP test."); + tcp_test(); + } + }); + + client_unix.addListener("error", function (e) { + throw e; + }); + + client_unix.addListener("close", function () { + server_unix.close(); + }); + }); + + server_unix.listen(unix_socket_path); +} + +unix_test(); +timer = setTimeout(function () { + assert.fail("Timeout"); +}, 1000); From 62d9852c3d6ed32825abfd79645c72a66fb00e6f Mon Sep 17 00:00:00 2001 From: Tim Caswell Date: Mon, 12 Apr 2010 11:57:24 -0500 Subject: [PATCH 68/73] Replace slow and broken for..in loops with faster for loops over the keys. --- lib/child_process.js | 8 +++--- lib/dns.js | 19 ++++++++------ lib/fs.js | 16 ++++++++++-- lib/http.js | 60 ++++++++++++++++++++++++++++---------------- lib/ini.js | 37 +++++++++++++++++---------- lib/querystring.js | 18 ++++++++----- lib/url.js | 6 ++++- src/node.js | 8 ++++-- 8 files changed, 115 insertions(+), 57 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index 4ed5a544a00..5a904422613 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -76,10 +76,10 @@ ChildProcess.prototype.spawn = function (path, args, env) { args = args || []; env = env || process.env; var envPairs = []; - for (var key in env) { - if (env.hasOwnProperty(key)) { - envPairs.push(key + "=" + env[key]); - } + var keys = Object.keys(env); + for (var index = 0, keysLength = keys.length; index < keysLength; index++) { + var key = keys[index]; + envPairs.push(key + "=" + env[key]); } var fds = this._internal.spawn(path, args, envPairs); diff --git a/lib/dns.js b/lib/dns.js index 6794ef426f1..9bfca4752e7 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -8,7 +8,9 @@ var activeWatchers = {}; var timer = new process.Timer(); timer.callback = function () { - for (var socket in activeWatchers) { + var sockets = Object.keys(activeWatchers); + for (var i = 0, l = sockets.length; i < l; i++) { + var socket = sockets[i]; var s = parseInt(socket); channel.processFD( watchers[socket].read ? s : dns.SOCKET_BAD , watchers[socket].write ? s : dns.SOCKET_BAD @@ -21,13 +23,16 @@ timer.callback = function () { function updateTimer() { timer.stop(); - for (var socket in activeWatchers) { // if !empty(activeWatchers) - var max = 20000; - var timeout = channel.timeout(max); + // Were just checking to see if activeWatchers is empty or not + for (var socket in activeWatchers) { + if (activeWatchers.hasOwnProperty(socket)) { + var max = 20000; + var timeout = channel.timeout(max); - timer.start(timeout, 0); - - return; + timer.start(timeout, 0); + // Short circuit the loop on first find. + return; + } } } diff --git a/lib/fs.js b/lib/fs.js index 4b2a4d120ad..c3ab698e633 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -490,7 +490,13 @@ var FileReadStream = fs.FileReadStream = function(path, options) { this.bufferSize = 4 * 1024; options = options || {}; - for (var i in options) this[i] = options[i]; + + // Mixin options into this + var keys = Object.keys(options); + for (var index = 0, length = keys.length; index < length; index++) { + var key = keys[index]; + this[key] = options[key]; + } var self = this; @@ -621,7 +627,13 @@ var FileWriteStream = fs.FileWriteStream = function(path, options) { this.mode = 0666; options = options || {}; - for (var i in options) this[i] = options[i]; + + // Mixin options into this + var keys = Object.keys(options); + for (var index = 0, length = keys.length; index < length; index++) { + var key = keys[index]; + this[key] = options[key]; + } this.busy = false; this._queue = []; diff --git a/lib/http.js b/lib/http.js index 12130b68b66..717085396d5 100644 --- a/lib/http.js +++ b/lib/http.js @@ -267,29 +267,34 @@ OutgoingMessage.prototype.sendHeaderLines = function (firstLine, headers) { // in the case of response it is: "HTTP/1.1 200 OK\r\n" var messageHeader = firstLine; var field, value; - for (var i in headers) { - if (headers[i] instanceof Array) { - field = headers[i][0]; - value = headers[i][1]; - } else { - if (!headers.hasOwnProperty(i)) continue; - field = i; - value = headers[i]; - } - messageHeader += field + ": " + value + CRLF; + if (headers) { + var keys = Object.keys(headers); + var isArray = (headers instanceof Array); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (isArray) { + field = headers[key][0]; + value = headers[key][1]; + } else { + field = key; + value = headers[key]; + } - if (connectionExpression.test(field)) { - sentConnectionHeader = true; - if (closeExpression.test(value)) this.closeOnFinish = true; + messageHeader += field + ": " + value + CRLF; - } else if (transferEncodingExpression.test(field)) { - sentTransferEncodingHeader = true; - if (chunkExpression.test(value)) this.chunkedEncoding = true; + if (connectionExpression.test(field)) { + sentConnectionHeader = true; + if (closeExpression.test(value)) this.closeOnFinish = true; - } else if (contentLengthExpression.test(field)) { - sentContentLengthHeader = true; + } else if (transferEncodingExpression.test(field)) { + sentTransferEncodingHeader = true; + if (chunkExpression.test(value)) this.chunkedEncoding = true; + } else if (contentLengthExpression.test(field)) { + sentContentLengthHeader = true; + + } } } @@ -696,10 +701,21 @@ exports.cat = function (url, encoding_, headers_) { var url = require("url").parse(url); var hasHost = false; - for (var i in headers) { - if (i.toLowerCase() === "host") { - hasHost = true; - break; + if (headers instanceof Array) { + for (var i = 0, l = headers.length; i < l; i++) { + if (headers[i][0].toLowerCase() === 'host') { + hasHost = true; + break; + } + } + } else if (typeof headers === "Object") { + var keys = Object.keys(headers); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (key.toLowerCase() == 'host') { + hasHost = true; + break; + } } } if (!hasHost) headers["Host"] = url.hostname; diff --git a/lib/ini.js b/lib/ini.js index 3a59457c605..ad309b719a0 100644 --- a/lib/ini.js +++ b/lib/ini.js @@ -42,24 +42,35 @@ function safe (val) { return (val+"").replace(/[\n\r]+/g, " "); } +// ForEaches over an object. The only thing faster is to inline this function. +function objectEach(obj, fn, thisObj) { + var keys, key, i, length; + keys = Object.keys(obj); + length = keys.length; + for (i = 0; i < length; i++) { + key = keys[i]; + fn.call(thisObj, obj[key], key, obj); + } +} + exports.stringify = function (obj) { // if the obj has a "-" section, then do that first. - var ini = ""; + var ini = []; if ("-" in obj) { - for (var key in obj["-"]) { - ini += safe(key)+" = "+safe(obj["-"][key])+"\n"; - } + objectEach(obj["-"], function (value, key) { + ini[ini.length] = safe(key) + " = " + safe(value) + "\n"; + }); } - for (var section in obj) if (section !== "-") { - ini += "[" + safe(section) + "]\n"; - for (var key in obj[section]) { - - ini += safe(key) + ((obj[section][key] === true) + objectEach(obj, function (section, name) { + if (name === "-") return; + ini[ini.length] = "[" + safe(name) + "]\n"; + objectEach(section, function (value, key) { + ini[ini.length] = safe(key) + ((value === true) ? "\n" - : " = "+safe(obj[section][key])+"\n"); - } - } - return ini; + : " = "+safe(value)+"\n"); + }); + }); + return ini.join(""); }; exports.encode = exports.stringify; diff --git a/lib/querystring.js b/lib/querystring.js index 5220b53ae99..83e0a0f85ed 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -55,9 +55,11 @@ QueryString.stringify = function (obj, sep, eq, name) { var s = []; var begin = name ? name + '[' : ''; var end = name ? ']' : ''; - for (var i in obj) if (obj.hasOwnProperty(i)) { - var n = begin + i + end; - s.push(QueryString.stringify(obj[i], sep, eq, n)); + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + var n = begin + key + end; + s.push(QueryString.stringify(obj[key], sep, eq, n)); } stack.pop(); @@ -138,10 +140,14 @@ function mergeParams (params, addition) { }; // Merge two *objects* together. If this is called, we've already ruled -// out the simple cases, and need to do the for-in business. +// out the simple cases, and need to do a loop. function mergeObjects (params, addition) { - for (var i in addition) if (i && addition.hasOwnProperty(i)) { - params[i] = mergeParams(params[i], addition[i]); + var keys = Object.keys(addition); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (key) { + params[key] = mergeParams(params[key], addition[key]); + } } return params; }; diff --git a/lib/url.js b/lib/url.js index e6f2d71ebe5..c4b534a5d5f 100644 --- a/lib/url.js +++ b/lib/url.js @@ -56,7 +56,11 @@ function urlParse (url, parseQueryString) { // pull out the auth and port. var p = parseHost(out.host); - for (var i in p) out[i] = p[i]; + var keys = Object.keys(p); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + out[key] = p[key]; + } // we've indicated that there is a hostname, so even if it's empty, it has to be present. out.hostname = out.hostname || ""; } diff --git a/src/node.js b/src/node.js index 675e3bc048f..eb703d93c79 100644 --- a/src/node.js +++ b/src/node.js @@ -462,7 +462,9 @@ function findModulePath (id, dirs, callback) { ]; var ext; - for (ext in extensionCache) { + var extensions = Object.keys(extensionCache); + for (var i = 0, l = extensions.length; i < l; i++) { + var ext = extensions[i]; locations.push(path.join(dir, id + ext)); locations.push(path.join(dir, id, 'index' + ext)); } @@ -504,7 +506,9 @@ function resolveModulePath(request, parent) { debug("RELATIVE: requested:" + request + " set ID to: "+id+" from "+parent.id); var exts = ['js', 'node'], ext; - for (ext in extensionCache) { + var extensions = Object.keys(extensionCache); + for (var i = 0, l = extensions.length; i < l; i++) { + var ext = extensions[i]; exts.push(ext.slice(1)); } From 4681e34c1e74e96f3027e88523dadf6b27a611c3 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 12 Apr 2010 12:34:24 -0700 Subject: [PATCH 69/73] Fix a race condition or two in net.js When making a TCP connection, readyState returns 'opening' while resolving the host. However between the resolving period and the establishing a connection period, it would return 'closed'. This fixes it. This change also ensures that the socket is closed before the 'end' event is emitted in the case that the socket was previously shutdown. --- lib/net.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/net.js b/lib/net.js index f3461c5b6e0..bf7caf64c7a 100644 --- a/lib/net.js +++ b/lib/net.js @@ -308,13 +308,15 @@ function initStream (self) { //debug('bytesRead ' + bytesRead + '\n'); if (bytesRead === 0) { + // EOF self.readable = false; self._readWatcher.stop(); + if (!self.writable) self.destroy(); + // Note: 'close' not emitted until nextTick. + if (self._events && self._events['end']) self.emit('end'); if (self.onend) self.onend(); - - if (!self.writable) self.destroy(); } else if (bytesRead > 0) { timeout.active(self); @@ -383,15 +385,19 @@ exports.createConnection = function (port, host) { Object.defineProperty(Stream.prototype, 'readyState', { get: function () { - if (this._resolving) { + if (this._connecting) { return 'opening'; } else if (this.readable && this.writable) { + assert(typeof this.fd == 'number'); return 'open'; } else if (this.readable && !this.writable){ + assert(typeof this.fd == 'number'); return 'readOnly'; } else if (!this.readable && this.writable){ + assert(typeof this.fd == 'number'); return 'writeOnly'; } else { + assert(typeof this.fd != 'number'); return 'closed'; } } @@ -580,16 +586,16 @@ function doConnect (socket, port, host) { // socketError() if there isn't an error, we're connected. AFAIK this a // platform independent way determining when a non-blocking connection // is established, but I have only seen it documented in the Linux - // Manual Page connect(2) under the error code EINPROGRESS. + // Manual Page connect(2) under the error code EINPROGRESS. socket._writeWatcher.set(socket.fd, false, true); socket._writeWatcher.start(); socket._writeWatcher.callback = function () { var errno = socketError(socket.fd); if (errno == 0) { // connection established + socket._connecting = false; socket.resume(); - socket.readable = true; - socket.writable = true; + socket.readable = socket.writable = true; socket._writeWatcher.callback = _doFlush; socket.emit('connect'); } else if (errno != EINPROGRESS) { @@ -611,27 +617,24 @@ Stream.prototype.connect = function () { timeout.active(socket); - var port = parseInt(arguments[0]); + self._connecting = true; // set false in doConnect - if (port >= 0) { - //debug('new fd = ' + self.fd); - // TODO dns resolution on arguments[1] + if (parseInt(arguments[0]) >= 0) { + // TCP var port = arguments[0]; - self._resolving = true; dns.lookup(arguments[1], function (err, ip, addressType) { if (err) { self.emit('error', err); } else { self.type = addressType == 4 ? 'tcp4' : 'tcp6'; self.fd = socket(self.type); - self._resolving = false; doConnect(self, port, ip); } }); } else { + // UNIX self.fd = socket('unix'); self.type = 'unix'; - // TODO check if sockfile exists? doConnect(self, arguments[0]); } }; @@ -683,6 +686,8 @@ Stream.prototype.destroy = function (exception) { // but lots of code assumes this._writeQueue is always an array. this._writeQueue = []; + this.readable = this.writable = false; + if (this._writeWatcher) { this._writeWatcher.stop(); ioWatchers.free(this._writeWatcher); From afe3c1cdea8cd88e04a09961567216606f5f0117 Mon Sep 17 00:00:00 2001 From: Matt Ranney Date: Mon, 12 Apr 2010 14:29:49 -0700 Subject: [PATCH 70/73] Buffer partial reads before doing expect match. --- test/simple/test-repl.js | 48 ++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/test/simple/test-repl.js b/test/simple/test-repl.js index 54511ce3dfd..65ee7cb27f2 100644 --- a/test/simple/test-repl.js +++ b/test/simple/test-repl.js @@ -40,6 +40,8 @@ function tcp_test() { }); server_tcp.addListener('listening', function () { + var read_buffer = ""; + client_tcp = net.createConnection(PORT); client_tcp.addListener('connect', function () { @@ -54,17 +56,23 @@ function tcp_test() { }); client_tcp.addListener('data', function (data) { - var data_str = data.asciiSlice(0, data.length); - sys.puts("TCP data: " + data_str + ", compare to " + client_tcp.expect); - assert.strictEqual(client_tcp.expect, data_str); - if (client_tcp.list && client_tcp.list.length > 0) { - send_expect(client_tcp.list); + read_buffer += data.asciiSlice(0, data.length); + sys.puts("TCP data: " + read_buffer + ", expecting " + client_tcp.expect); + if (read_buffer.indexOf(prompt_tcp) !== -1) { + assert.strictEqual(client_tcp.expect, read_buffer); + read_buffer = ""; + if (client_tcp.list && client_tcp.list.length > 0) { + send_expect(client_tcp.list); + } + else { + sys.puts("End of TCP test."); + client_tcp.end(); + client_unix.end(); + clearTimeout(timer); + } } else { - sys.puts("End of TCP test."); - client_tcp.end(); - client_unix.end(); - clearTimeout(timer); + sys.puts("didn't see prompt yet, buffering"); } }); @@ -93,6 +101,8 @@ function unix_test() { }); server_unix.addListener('listening', function () { + var read_buffer = ""; + client_unix = net.createConnection(unix_socket_path); client_unix.addListener('connect', function () { @@ -108,15 +118,21 @@ function unix_test() { }); client_unix.addListener('data', function (data) { - var data_str = data.asciiSlice(0, data.length); - sys.puts("Unix data: " + data_str + ", compare to " + client_unix.expect); - assert.strictEqual(client_unix.expect, data_str); - if (client_unix.list && client_unix.list.length > 0) { - send_expect(client_unix.list); + read_buffer += data.asciiSlice(0, data.length); + sys.puts("Unix data: " + read_buffer + ", expecting " + client_unix.expect); + if (read_buffer.indexOf(prompt_unix) !== -1) { + assert.strictEqual(client_unix.expect, read_buffer); + read_buffer = ""; + if (client_unix.list && client_unix.list.length > 0) { + send_expect(client_unix.list); + } + else { + sys.puts("End of Unix test, running TCP test."); + tcp_test(); + } } else { - sys.puts("End of Unix test, running TCP test."); - tcp_test(); + sys.puts("didn't see prompt yet, bufering."); } }); From 1efd26157289ae52bf190dd044daf92b1db8fb80 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 12 Apr 2010 16:27:04 -0700 Subject: [PATCH 71/73] doc typo --- doc/api.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/api.markdown b/doc/api.markdown index 525743c3a4a..00d43069d2b 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1367,9 +1367,7 @@ is ready to accept connections. ### server.listen(path) -Start an HTTP UNIX socket server listening for connections on the given `path`. -(Hint: use NGINX to load balance across many Node servers with this.) - +Start a UNIX socket server listening for connections on the given `path`. This function is asynchronous. `listening` will be emitted when the server is ready to accept connections. From b7947e45c092df8b032f3b689a020ed972ef485a Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 12 Apr 2010 16:34:39 -0700 Subject: [PATCH 72/73] Recycle http client parsers --- lib/http.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/http.js b/lib/http.js index 717085396d5..8523bd63019 100644 --- a/lib/http.js +++ b/lib/http.js @@ -616,6 +616,8 @@ function Client ( ) { // If there are more requests to handle, reconnect. if (requests.length > 0) { self._reconnect(); + } else { + freeParser(parser); } }); From 57ea07ac912d88fb947a95ffd502c23f2d60f8b9 Mon Sep 17 00:00:00 2001 From: Micheil Smith Date: Tue, 13 Apr 2010 02:27:32 +1000 Subject: [PATCH 73/73] Moving the http.js, net.js FreeList to being standalone. --- lib/freelist.js | 22 +++++++ lib/http.js | 162 +++++++++++++++++++++++------------------------- lib/net.js | 30 +-------- src/node.cc | 1 + 4 files changed, 101 insertions(+), 114 deletions(-) create mode 100644 lib/freelist.js diff --git a/lib/freelist.js b/lib/freelist.js new file mode 100644 index 00000000000..a09fb4b21e5 --- /dev/null +++ b/lib/freelist.js @@ -0,0 +1,22 @@ +// This is a free list to avoid creating so many of the same object. +exports.FreeList = function(name, max, constructor) { + this.name = name; + this.constructor = constructor; + this.max = max; + this.list = []; +} + + +exports.FreeList.prototype.alloc = function () { + //debug("alloc " + this.name + " " + this.list.length); + return this.list.length ? this.list.shift() + : this.constructor.apply(this, arguments); +}; + + +exports.FreeList.prototype.free = function (obj) { + //debug("free " + this.name + " " + this.list.length); + if (this.list.length < this.max) { + this.list.push(obj); + } +}; diff --git a/lib/http.js b/lib/http.js index 8523bd63019..28e3e3e2498 100644 --- a/lib/http.js +++ b/lib/http.js @@ -11,101 +11,91 @@ var sys = require('sys'); var net = require('net'); var events = require('events'); +var FreeList = require('freelist').FreeList; var HTTPParser = process.binding('http_parser').HTTPParser; -var parserFreeList = []; +var parsers = new FreeList('parsers', 1000, function () { + var parser = new HTTPParser('request'); -function newParser (type) { - var parser; - if (parserFreeList.length) { - parser = parserFreeList.shift(); - parser.reinitialize(type); - } else { - parser = new HTTPParser(type); + parser.onMessageBegin = function () { + parser.incoming = new IncomingMessage(parser.socket); + parser.field = null; + parser.value = null; + }; - parser.onMessageBegin = function () { - parser.incoming = new IncomingMessage(parser.socket); + // Only servers will get URL events. + parser.onURL = function (b, start, len) { + var slice = b.toString('ascii', start, start+len); + if (parser.incoming.url) { + parser.incoming.url += slice; + } else { + // Almost always will branch here. + parser.incoming.url = slice; + } + }; + + parser.onHeaderField = function (b, start, len) { + var slice = b.toString('ascii', start, start+len).toLowerCase(); + if (parser.value) { + parser.incoming._addHeaderLine(parser.field, parser.value); parser.field = null; parser.value = null; - }; + } + if (parser.field) { + parser.field += slice; + } else { + parser.field = slice; + } + }; - // Only servers will get URL events. - parser.onURL = function (b, start, len) { - var slice = b.toString('ascii', start, start+len); - if (parser.incoming.url) { - parser.incoming.url += slice; - } else { - // Almost always will branch here. - parser.incoming.url = slice; - } - }; + parser.onHeaderValue = function (b, start, len) { + var slice = b.toString('ascii', start, start+len); + if (parser.value) { + parser.value += slice; + } else { + parser.value = slice; + } + }; - parser.onHeaderField = function (b, start, len) { - var slice = b.toString('ascii', start, start+len).toLowerCase(); - if (parser.value) { - parser.incoming._addHeaderLine(parser.field, parser.value); - parser.field = null; - parser.value = null; - } - if (parser.field) { - parser.field += slice; - } else { - parser.field = slice; - } - }; + parser.onHeadersComplete = function (info) { + if (parser.field && parser.value) { + parser.incoming._addHeaderLine(parser.field, parser.value); + } - parser.onHeaderValue = function (b, start, len) { - var slice = b.toString('ascii', start, start+len); - if (parser.value) { - parser.value += slice; - } else { - parser.value = slice; - } - }; + parser.incoming.httpVersionMajor = info.versionMajor; + parser.incoming.httpVersionMinor = info.versionMinor; + parser.incoming.httpVersion = info.versionMajor + + '.' + + info.versionMinor ; - parser.onHeadersComplete = function (info) { - if (parser.field && parser.value) { - parser.incoming._addHeaderLine(parser.field, parser.value); - } + if (info.method) { + // server only + parser.incoming.method = info.method; + } else { + // client only + parser.incoming.statusCode = info.statusCode; + } - parser.incoming.httpVersionMajor = info.versionMajor; - parser.incoming.httpVersionMinor = info.versionMinor; - parser.incoming.httpVersion = info.versionMajor - + '.' - + info.versionMinor ; + parser.onIncoming(parser.incoming, info.shouldKeepAlive); + }; - if (info.method) { - // server only - parser.incoming.method = info.method; - } else { - // client only - parser.incoming.statusCode = info.statusCode; - } + parser.onBody = function (b, start, len) { + // TODO body encoding? + var enc = parser.incoming._encoding; + if (!enc) { + parser.incoming.emit('data', b.slice(start, start+len)); + } else { + var string = b.toString(enc, start, start+len); + parser.incoming.emit('data', string); + } + }; - parser.onIncoming(parser.incoming, info.shouldKeepAlive); - }; + parser.onMessageComplete = function () { + parser.incoming.emit("end"); + }; - parser.onBody = function (b, start, len) { - // TODO body encoding? - var enc = parser.incoming._encoding; - if (!enc) { - parser.incoming.emit('data', b.slice(start, start+len)); - } else { - var string = b.toString(enc, start, start+len); - parser.incoming.emit('data', string); - } - }; - - parser.onMessageComplete = function () { - parser.incoming.emit("end"); - }; - } return parser; -} - -function freeParser (parser) { - if (parserFreeList.length < 1000) parserFreeList.push(parser); -} +}); var CRLF = "\r\n"; @@ -517,7 +507,9 @@ function connectionListener (socket) { // we need to keep track of the order they were sent. var responses = []; - var parser = newParser('request'); + var parser = parsers.alloc(); + parser.reinitialize('request'); + parser.socket = socket; socket.ondata = function (d, start, end) { parser.execute(d, start, end - start); @@ -526,7 +518,7 @@ function connectionListener (socket) { socket.onend = function () { parser.finish(); // unref the parser for easy gc - freeParser(parser); + parsers.free(parser); if (responses.length == 0) { socket.end(); @@ -535,7 +527,6 @@ function connectionListener (socket) { } }; - parser.socket = socket; // The following callback is issued after the headers have been read on a // new message. In this callback we setup the response object and pass it // to the user. @@ -563,7 +554,8 @@ function Client ( ) { var requests = []; var currentRequest; - var parser = newParser('response'); + var parser = parsers.alloc(); + parser.reinitialize('response'); parser.socket = this; self._reconnect = function () { @@ -617,7 +609,7 @@ function Client ( ) { if (requests.length > 0) { self._reconnect(); } else { - freeParser(parser); + parsers.free(parser); } }); diff --git a/lib/net.js b/lib/net.js index bf7caf64c7a..72eb878c8e9 100644 --- a/lib/net.js +++ b/lib/net.js @@ -22,6 +22,7 @@ var binding = process.binding('net'); // yet convinced that every use-case can be fit into that abstraction, so // waiting to implement it until I get more experience with this. var Buffer = require('buffer').Buffer; +var FreeList = require('freelist').FreeList; var IOWatcher = process.IOWatcher; var assert = process.assert; @@ -205,35 +206,6 @@ var timeout = new (function () { }; })(); - - - - -// This is a free list to avoid creating so many of the same object. - -function FreeList (name, max, constructor) { - this.name = name; - this.constructor = constructor; - this.max = max; - this.list = []; -} - - -FreeList.prototype.alloc = function () { - //debug("alloc " + this.name + " " + this.list.length); - return this.list.length ? this.list.shift() - : this.constructor.apply(this, arguments); -}; - - -FreeList.prototype.free = function (obj) { - //debug("free " + this.name + " " + this.list.length); - if (this.list.length < this.max) { - this.list.push(obj); - } -}; - - var ioWatchers = new FreeList("iowatcher", 100, function () { return new IOWatcher(); }); diff --git a/src/node.cc b/src/node.cc index 131b8ca667d..28b97ce95f1 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1268,6 +1268,7 @@ static Handle Binding(const Arguments& args) { exports->Set(String::New("dns"), String::New(native_dns)); exports->Set(String::New("events"), String::New(native_events)); exports->Set(String::New("file"), String::New(native_file)); + exports->Set(String::New("freelist"), String::New(native_freelist)); exports->Set(String::New("fs"), String::New(native_fs)); exports->Set(String::New("http"), String::New(native_http)); exports->Set(String::New("http_old"), String::New(native_http_old));