X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=net%2Fadns.lua;h=cd69a627e044f69182ee59d5f0586ba1d6e6a17a;hb=9219b5b35c5be9687eafac1f840246c10352905e;hp=cb784d405642d9f9469fc06a4aec989d307bb5fd;hpb=ce30d543330e423952342c08e62d1b30d5618a28;p=prosody.git diff --git a/net/adns.lua b/net/adns.lua index cb784d40..cd69a627 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -1,40 +1,91 @@ +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + local server = require "net.server"; local dns = require "net.dns"; local log = require "util.logger".init("adns"); -local coroutine, tostring = coroutine, tostring; +local t_insert, t_remove = table.insert, table.remove; +local coroutine, tostring, pcall = coroutine, tostring, pcall; + +local function dummy_send(sock, data, i, j) return (j-i)+1; end module "adns" function lookup(handler, qname, qtype, qclass) - return dns.peek(qname, qtype, qclass) or - coroutine.wrap(function () - log("debug", "Records for "..qname.." not in cache, sending query (%s)...", tostring(coroutine.running())); - dns.query(qname, qtype, qclass); - coroutine.yield(nil); -- Wait for reply - log("debug", "Reply for "..qname.." (%s)", tostring(coroutine.running())); - handler(dns.peek(qname, qtype, qclass)); - end)(); + return coroutine.wrap(function (peek) + if peek then + log("debug", "Records for %s already cached, using those...", qname); + handler(peek); + return; + end + log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); + local ok, err = dns.query(qname, qtype, qclass); + if ok then + coroutine.yield({ qclass or "IN", qtype or "A", qname, coroutine.running()}); -- Wait for reply + log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); + end + if ok then + ok, err = pcall(handler, dns.peek(qname, qtype, qclass)); + else + log("error", "Error sending DNS query: %s", err); + ok, err = pcall(handler, nil, err); + end + if not ok then + log("error", "Error in DNS response handler: %s", tostring(err)); + end + end)(dns.peek(qname, qtype, qclass)); +end + +function cancel(handle, call_handler, reason) + log("warn", "Cancelling DNS lookup for %s", tostring(handle[3])); + dns.cancel(handle[1], handle[2], handle[3], handle[4], call_handler); end -function new_async_socket(sock) - local newconn = {}; +function new_async_socket(sock, resolver) + local peername = ""; local listener = {}; - function listener.incoming(conn, data) - dns.feed(sock, data); + local handler = {}; + function listener.onincoming(conn, data) + if data then + dns.feed(handler, data); + end + end + function listener.ondisconnect(conn, err) + if err then + log("warn", "DNS socket for %s disconnected: %s", peername, err); + local servers = resolver.server; + if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then + log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]); + end + + resolver:servfail(conn); -- Let the magic commence + end + end + handler = server.wrapclient(sock, "dns", 53, listener); + if not handler then + log("warn", "handler is nil"); end - function listener.disconnect() + + handler.settimeout = function () end + handler.setsockname = function (_, ...) return sock:setsockname(...); end + handler.setpeername = function (_, ...) peername = (...); local ret = sock:setpeername(...); _:set_send(dummy_send); return ret; end + handler.connect = function (_, ...) return sock:connect(...) end + --handler.send = function (_, data) _:write(data); return _.sendbuffer and _.sendbuffer(); end + handler.send = function (_, data) + local getpeername = sock.getpeername; + log("debug", "Sending DNS query to %s", (getpeername and getpeername(sock)) or ""); + return sock:send(data); end - newconn.handler, newconn._socket = server.wrapclient(sock, "dns", 53, listener); - newconn.handler.settimeout = function () end - newconn.handler.setsockname = function (_, ...) return sock:setsockname(...); end - newconn.handler.setpeername = function (_, ...) local ret = sock:setpeername(...); _.setsend(sock.send); return ret; end - newconn.handler.connect = function (_, ...) return sock:connect(...) end - newconn.handler.send = function (_, data) return _.write(data) end - return newconn.handler; + return handler; end -dns:socket_wrapper_set(new_async_socket); +dns.socket_wrapper_set(new_async_socket); return _M;