From f3f4b12eb59de6d9d8a77fed797b47702b3fd4df Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 18 Aug 2009 15:58:44 +0100 Subject: net.server: Add checking for nil sockets to prevent traceback --- net/server.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/server.lua b/net/server.lua index 966006c1..12b0aa90 100644 --- a/net/server.lua +++ b/net/server.lua @@ -483,13 +483,19 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport end end local _sendbuffer = function( ) -- this function sends data - local buffer = table_concat( bufferqueue, "", 1, bufferqueuelen ) - local succ, err, byte = send( socket, buffer, 1, bufferlen ) - local count = ( succ or byte or 0 ) * STAT_UNIT - sendtraffic = sendtraffic + count - _sendtraffic = _sendtraffic + count - _ = _cleanqueue and clean( bufferqueue ) - --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) ) + local succ, err, byte, buffer, count; + local count; + if socket then + buffer = table_concat( bufferqueue, "", 1, bufferqueuelen ) + succ, err, byte = send( socket, buffer, 1, bufferlen ) + count = ( succ or byte or 0 ) * STAT_UNIT + sendtraffic = sendtraffic + count + _sendtraffic = _sendtraffic + count + _ = _cleanqueue and clean( bufferqueue ) + --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) ) + else + succ, err, count = false, "closed", 0; + end if succ then -- sending succesful bufferqueuelen = 0 bufferlen = 0 -- cgit v1.2.3 From 243f4c0fb35b75a3ca120c8e076ca7e7458c1c77 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 18 Sep 2009 02:45:15 +0100 Subject: net.dns: Multiple internal changes and API extensions to allow for more reliable DNS lookups --- net/dns.lua | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/dns.lua b/net/dns.lua index 48c08218..ff07d26e 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -17,6 +17,7 @@ require 'socket' local ztact = require 'util.ztact' local require = require +local os = os; local coroutine, io, math, socket, string, table = coroutine, io, math, socket, string, table @@ -487,7 +488,7 @@ function resolver:decode (packet, force) -- - - - - - - - - - - - - - decode -- socket layer -------------------------------------------------- socket layer -resolver.delays = { 1, 3, 11, 45 } +resolver.delays = { 1, 3 } function resolver:addnameserver (address) -- - - - - - - - - - addnameserver @@ -509,9 +510,12 @@ function resolver:adddefaultnameservers () -- - - - - adddefaultnameservers local address = string.match (line, 'nameserver%s+(%d+%.%d+%.%d+%.%d+)') if address then self:addnameserver (address) end end - else -- FIXME correct for windows, using opendns nameservers for now - self:addnameserver ("208.67.222.222") - self:addnameserver ("208.67.220.220") + elseif os.getenv("WINDIR") then + self:addnameserver ("208.67.222.222") + self:addnameserver ("208.67.220.220") + end + if not self.server or #self.server == 0 then + self:addnameserver("127.0.0.1"); end end @@ -525,16 +529,25 @@ function resolver:getsocket (servernum) -- - - - - - - - - - - - - getsocket if sock then return sock end sock = socket.udp () - if self.socket_wrapper then sock = self.socket_wrapper (sock) end + if self.socket_wrapper then sock = self.socket_wrapper (sock, self) end sock:settimeout (0) -- todo: attempt to use a random port, fallback to 0 sock:setsockname ('*', 0) sock:setpeername (self.server[servernum], 53) self.socket[servernum] = sock - self.socketset[sock] = sock + self.socketset[sock] = servernum return sock end +function resolver:voidsocket (sock) + if self.socket[sock] then + self.socketset[self.socket[sock]] = nil + self.socket[sock] = nil + elseif self.socketset[sock] then + self.socket[self.socketset[sock]] = nil + self.socketset[sock] = nil + end +end function resolver:socket_wrapper_set (func) -- - - - - - - socket_wrapper_set self.socket_wrapper = func @@ -608,10 +621,9 @@ function resolver:query (qname, qtype, qclass) -- - - - - - - - - - -- query local header, id = encodeHeader () --print ('query id', id, qclass, qtype, qname) local o = { packet = header..question, - server = 1, + server = self.best_server, delay = 1, retry = socket.gettime () + self.delays[1] } - self:getsocket (o.server):send (o.packet) -- remember the query self.active[id] = self.active[id] or {} @@ -623,9 +635,49 @@ function resolver:query (qname, qtype, qclass) -- - - - - - - - - - -- query set (self.wanted, qclass, qtype, qname, co, true) --set (self.yielded, co, qclass, qtype, qname, true) end + + self:getsocket (o.server):send (o.packet) + end +function resolver:servfail(sock) + -- Resend all queries for this server + + local num = self.socketset[sock] + + -- Socket is dead now + self:voidsocket(sock); + + -- Find all requests to the down server, and retry on the next server + self.time = socket.gettime () + for id,queries in pairs (self.active) do + for question,o in pairs (queries) do + if o.server == num then -- This request was to the broken server + o.server = o.server + 1 -- Use next server + if o.server > #self.server then + o.server = 1 + end + o.retries = (o.retries or 0) + 1; + if o.retries >= #self.server then + --print ('timeout') + queries[question] = nil + else + local _a = self:getsocket(o.server); + if _a then _a:send (o.packet) end + end + end + end + end + + if num == self.best_server then + self.best_server = self.best_server + 1 + if self.best_server > #self.server then + -- Exhausted all servers, try first again + self.best_server = 1 + end + end +end function resolver:receive (rset) -- - - - - - - - - - - - - - - - - receive @@ -828,7 +880,8 @@ function dns.resolver () -- - - - - - - - - - - - - - - - - - - - - resolver -- this function seems to be redundant with resolver.new () - local r = { active = {}, cache = {}, unsorted = {}, wanted = {}, yielded = {} } + local r = { active = {}, cache = {}, unsorted = {}, wanted = {}, yielded = {}, + best_server = 1 } setmetatable (r, resolver) setmetatable (r.cache, cache_metatable) setmetatable (r.unsorted, { __mode = 'kv' }) -- cgit v1.2.3 From 97c697c83e00be46bb38e8b5e972f36aa900582e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 18 Sep 2009 02:46:11 +0100 Subject: net.adns: Utilise new net.dns API to handle DNS network errors --- net/adns.lua | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/adns.lua b/net/adns.lua index 34ef5d77..9438bf45 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -11,6 +11,7 @@ local dns = require "net.dns"; local log = require "util.logger".init("adns"); +local t_insert, t_remove = table.insert, table.remove; local coroutine, tostring, pcall = coroutine, tostring, pcall; module "adns" @@ -41,18 +42,31 @@ function cancel(handle, call_handler) end end -function new_async_socket(sock) - local newconn = {}; +function new_async_socket(sock, resolver) + local newconn, peername = {}, ""; local listener = {}; function listener.incoming(conn, data) dns.feed(sock, data); end - function listener.disconnect() + function listener.disconnect(conn, err) + log("warn", "DNS socket for %s disconnected: %s", peername, err); + local servers = resolver.server; + if resolver.socketset[newconn.handler] == 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 newconn.handler, newconn._socket = server.wrapclient(sock, "dns", 53, listener); + if not newconn.handler then + log("warn", "handler is nil"); + end + if not newconn._socket then + log("warn", "socket is nil"); + end 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.setpeername = function (_, ...) peername = (...); local ret = sock:setpeername(...); _.setsend(sock.send); return ret; end newconn.handler.connect = function (_, ...) return sock:connect(...) end newconn.handler.send = function (_, data) _.write(data); return _.sendbuffer(); end return newconn.handler; -- cgit v1.2.3