Software /
code /
prosody
Comparison
net/adns.lua @ 8266:9a97dd174ec9
net.adns: Restructure to allow creating separate resolver objects, like net.dns
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Mon, 25 Sep 2017 23:06:00 +0100 |
parent | 7475:ee878fa78b8b |
child | 8280:9ca0e3128b62 |
comparison
equal
deleted
inserted
replaced
8265:17ebd8ac8545 | 8266:9a97dd174ec9 |
---|---|
5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
7 -- | 7 -- |
8 | 8 |
9 local server = require "net.server"; | 9 local server = require "net.server"; |
10 local dns = require "net.dns"; | 10 local new_resolver = require "net.dns".resolver; |
11 | 11 |
12 local log = require "util.logger".init("adns"); | 12 local log = require "util.logger".init("adns"); |
13 | 13 |
14 local coroutine, tostring, pcall = coroutine, tostring, pcall; | 14 local coroutine, tostring, pcall = coroutine, tostring, pcall; |
15 | 15 |
16 local function dummy_send(sock, data, i, j) return (j-i)+1; end | 16 local function dummy_send(sock, data, i, j) return (j-i)+1; end |
17 | 17 |
18 local _ENV = nil; | 18 local _ENV = nil; |
19 | 19 |
20 local function lookup(handler, qname, qtype, qclass) | 20 local async_resolver_methods = {}; |
21 return coroutine.wrap(function (peek) | 21 local async_resolver_mt = { __index = async_resolver_methods }; |
22 if peek then | |
23 log("debug", "Records for %s already cached, using those...", qname); | |
24 handler(peek); | |
25 return; | |
26 end | |
27 log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); | |
28 local ok, err = dns.query(qname, qtype, qclass); | |
29 if ok then | |
30 coroutine.yield({ qclass or "IN", qtype or "A", qname, coroutine.running()}); -- Wait for reply | |
31 log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); | |
32 end | |
33 if ok then | |
34 ok, err = pcall(handler, dns.peek(qname, qtype, qclass)); | |
35 else | |
36 log("error", "Error sending DNS query: %s", err); | |
37 ok, err = pcall(handler, nil, err); | |
38 end | |
39 if not ok then | |
40 log("error", "Error in DNS response handler: %s", tostring(err)); | |
41 end | |
42 end)(dns.peek(qname, qtype, qclass)); | |
43 end | |
44 | 22 |
45 local function cancel(handle, call_handler, reason) | 23 local query_methods = {}; |
46 log("warn", "Cancelling DNS lookup for %s", tostring(handle[3])); | 24 local query_mt = { __index = query_methods }; |
47 dns.cancel(handle[1], handle[2], handle[3], handle[4], call_handler); | |
48 end | |
49 | 25 |
50 local function new_async_socket(sock, resolver) | 26 local function new_async_socket(sock, resolver) |
51 local peername = "<unknown>"; | 27 local peername = "<unknown>"; |
52 local listener = {}; | 28 local listener = {}; |
53 local handler = {}; | 29 local handler = {}; |
54 local err; | 30 local err; |
55 function listener.onincoming(conn, data) | 31 function listener.onincoming(conn, data) |
56 if data then | 32 if data then |
57 dns.feed(handler, data); | 33 resolver:feed(handler, data); |
58 end | 34 end |
59 end | 35 end |
60 function listener.ondisconnect(conn, err) | 36 function listener.ondisconnect(conn, err) |
61 if err then | 37 if err then |
62 log("warn", "DNS socket for %s disconnected: %s", peername, err); | 38 log("warn", "DNS socket for %s disconnected: %s", peername, err); |
83 return sock:send(data); | 59 return sock:send(data); |
84 end | 60 end |
85 return handler; | 61 return handler; |
86 end | 62 end |
87 | 63 |
88 dns.socket_wrapper_set(new_async_socket); | 64 function async_resolver_methods:lookup(handler, qname, qtype, qclass) |
65 local resolver = self._resolver; | |
66 return coroutine.wrap(function (peek) | |
67 if peek then | |
68 log("debug", "Records for %s already cached, using those...", qname); | |
69 handler(peek); | |
70 return; | |
71 end | |
72 log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); | |
73 local ok, err = resolver:query(qname, qtype, qclass); | |
74 if ok then | |
75 coroutine.yield(setmetatable({ resolver, qclass or "IN", qtype or "A", qname, coroutine.running()}, query_mt)); -- Wait for reply | |
76 log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); | |
77 end | |
78 if ok then | |
79 ok, err = pcall(handler, resolver:peek(qname, qtype, qclass)); | |
80 else | |
81 log("error", "Error sending DNS query: %s", err); | |
82 ok, err = pcall(handler, nil, err); | |
83 end | |
84 if not ok then | |
85 log("error", "Error in DNS response handler: %s", tostring(err)); | |
86 end | |
87 end)(resolver:peek(qname, qtype, qclass)); | |
88 end | |
89 | |
90 function query_methods:cancel(call_handler, reason) | |
91 log("warn", "Cancelling DNS lookup for %s", tostring(self[4])); | |
92 self[1].cancel(self[2], self[3], self[4], self[5], call_handler); | |
93 end | |
94 | |
95 local function new_async_resolver() | |
96 local resolver = new_resolver(); | |
97 resolver:socket_wrapper_set(new_async_socket); | |
98 return setmetatable({ _resolver = resolver}, async_resolver_mt); | |
99 end | |
89 | 100 |
90 return { | 101 return { |
91 lookup = lookup; | 102 lookup = function (...) |
92 cancel = cancel; | 103 return new_async_resolver():lookup(...); |
104 end; | |
105 resolver = new_async_resolver; | |
93 new_async_socket = new_async_socket; | 106 new_async_socket = new_async_socket; |
94 }; | 107 }; |