-
Notifications
You must be signed in to change notification settings - Fork 1
/
mdns_discovery.lua
173 lines (140 loc) · 4.05 KB
/
mdns_discovery.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: mdns_discovery.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Tue Mar 5 11:57:53 2013 mstenber
-- Last modified: Mon Nov 4 15:33:18 2013 mstenber
-- Edit time: 30 min
--
-- This is mdns discovery module.
-- What it does, is allows for discovery of the services present on
-- network that haven't been learned of through normal announce
-- process (due to them being up before the mdns.lua is started, or
-- due to network flaps).
-- Basic algorithm:
-- REDUNDANT_FREQUENCY is the time over which we verify that the list
-- of services and the individual service instances are valid
-- We maintain skiplist of what to check, and when, and also dns_db, so
-- that a) lookups are linear time, and so are the to do handling
-- updates etc.
-- This is a stand-alone class mostly for ease of unit testing; in
-- practise, it is closely bound to single mdns_if subclass, as it
-- assumes cache_changed_rr notifications to be propagated here, as
-- well as ability to call the time/query API as needed.
-- Inbound calls:
-- - cache_changed_rr(rr, is_add)
-- - next_time [ to find out when we next want to run ]
-- - run [ to actually run this - i.e. send queries ]
-- Outbound calls:
-- - time (to get current time)
-- - query (to send a query)
require 'mst'
require 'dns_db'
module(..., package.seeall)
-- every minute, even without any indication we should, we _will_ do things
REDUNDANT_FREQUENCY=60
-- (note that this should be ~order of magnitude less than maximum ttl
-- if set (in e.g. hp_core, mdns_core)
SD_ROOT={'_services', '_dns-sd', '_udp', 'local'}
mdns_discovery = mst.create_class{class='mdns_discovery',
mandatory={'query',
'time'},
}
function next_is_less(o1, o2)
return o1.next < o2.next
end
function mdns_discovery:init()
self.ns = dns_db.ns:new{}
self.sl = mst_skiplist.ipi_skiplist:new{lt=next_is_less}
self:insert_rr{name=SD_ROOT}
end
function mdns_discovery:insert_rr(rr)
rr.rtype = rr.rtype or dns_const.TYPE_PTR
rr.rclass = rr.rclass or dns_const.CLASS_IN
-- if we already have it, do nothing
local o = self.ns:find_rr(rr)
if o then return end
-- we don't have it
local o = self.ns:insert_rr(rr)
-- ask for it immediately
o.next = self.time()
self.sl:insert(o)
end
function mdns_discovery:remove_rr(rr)
rr.rtype = rr.rtype or dns_const.TYPE_PTR
rr.rclass = rr.rclass or dns_const.CLASS_IN
local o = self.ns:find_rr(rr)
if not o then return end
self.sl:remove_if_present(o)
self.ns:remove_rr(o)
end
function mdns_discovery:cache_changed_rr(rr, add)
-- ignore non-PTRs
if rr.rtype ~= dns_const.TYPE_PTR
then
return
end
-- we _only_ care about direct descendants of SD_ROOT (=services).
-- the instances are handled within mdns_if, as results of queries
-- we generate willy nilly here..
if not dns_db.ll_equal(SD_ROOT, rr.name)
then
return
end
if not add
then
self:remove_rr{name=rr.rdata_ptr}
return
end
self:insert_rr{name=rr.rdata_ptr}
end
function mdns_discovery:next_time()
local o = self.sl:get_first()
if o
then
return o.next
end
end
function mdns_discovery:should_run()
local nt = self:next_time()
if nt and nt <= self.time()
then
return true
end
end
function mdns_discovery:run()
local now = self.time()
local t
while true
do
local o = self.sl:get_first()
if not o or o.next > now
then
break
end
local q = {name=o.name,
qclass=o.rclass,
qtype=o.rtype,
}
self:d('performing discovery query', q)
-- send query
self.query(q)
-- update the next-to-run time
self.sl:remove(o)
t = t or {}
table.insert(t, o)
end
if t
then
for i, o in ipairs(t)
do
o.next = now + REDUNDANT_FREQUENCY
self.sl:insert(o)
end
end
end