dnsruby 1.37 → 1.38
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/Dnsruby/resource/DNSKEY.rb +3 -1
- data/lib/Dnsruby/resource/RRSIG.rb +1 -1
- data/lib/Dnsruby/resource/resource.rb +2 -0
- data/lib/Dnsruby/single_verifier.rb +41 -39
- data/lib/dnsruby.rb +2 -1
- data/test/tc_verifier.rb +82 -2
- metadata +3 -15
- data/demo/digroot.rb +0 -92
- data/html/created.rid +0 -1
- data/html/fr_class_index.html +0 -117
- data/html/fr_file_index.html +0 -82
- data/html/fr_method_index.html +0 -364
- data/html/index.html +0 -24
- data/lib/Dnsruby/resource/delete_me.rhtml +0 -6
- data/lib/Dnsruby/select_thread.rb.michael.rb +0 -602
- data/test/tc_auth.rb +0 -49
- data/test/ts_queue.rb +0 -3
data/html/index.html
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
-
<!DOCTYPE html
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
5
|
-
|
6
|
-
<!--
|
7
|
-
|
8
|
-
RDoc Documentation
|
9
|
-
|
10
|
-
-->
|
11
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
12
|
-
<head>
|
13
|
-
<title>RDoc Documentation</title>
|
14
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
15
|
-
</head>
|
16
|
-
<frameset rows="20%, 80%">
|
17
|
-
<frameset cols="25%,35%,45%">
|
18
|
-
<frame src="fr_file_index.html" title="Files" name="Files" />
|
19
|
-
<frame src="fr_class_index.html" name="Classes" />
|
20
|
-
<frame src="fr_method_index.html" name="Methods" />
|
21
|
-
</frameset>
|
22
|
-
<frame src="classes/Dnsruby.html" name="docwin" />
|
23
|
-
</frameset>
|
24
|
-
</html>
|
@@ -1,602 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
#Copyright 2007 Nominet UK
|
3
|
-
#
|
4
|
-
#Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
#you may not use this file except in compliance with the License.
|
6
|
-
#You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
#Unless required by applicable law or agreed to in writing, software
|
11
|
-
#distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
#See the License for the specific language governing permissions and
|
14
|
-
#limitations under the License.
|
15
|
-
#++
|
16
|
-
require 'socket'
|
17
|
-
#require 'thread'
|
18
|
-
begin
|
19
|
-
require 'fastthread'
|
20
|
-
rescue LoadError
|
21
|
-
require 'thread'
|
22
|
-
end
|
23
|
-
require 'singleton'
|
24
|
-
require 'Dnsruby/validator_thread.rb'
|
25
|
-
module Dnsruby
|
26
|
-
Thread::abort_on_exception = true
|
27
|
-
class SelectThread #:nodoc: all
|
28
|
-
class SelectWakeup < RuntimeError; end
|
29
|
-
include Singleton
|
30
|
-
# This singleton class runs a continuous select loop which
|
31
|
-
# listens for responses on all of the in-use sockets.
|
32
|
-
# When a new query is sent, the thread is woken up, and
|
33
|
-
# the socket is added to the select loop (and the new timeout
|
34
|
-
# calculated).
|
35
|
-
# Note that a combination of the socket and the packet ID is
|
36
|
-
# sufficient to uniquely identify the query to the select thread.
|
37
|
-
#
|
38
|
-
# But how do we find the response queue for a particular query?
|
39
|
-
# Hash of client_id->[query, client_queue, socket]
|
40
|
-
# and socket->[client_id]
|
41
|
-
#
|
42
|
-
# @todo@ should we implement some of cancel function?
|
43
|
-
|
44
|
-
def initialize
|
45
|
-
@@mutex = Mutex.new
|
46
|
-
@@mutex.synchronize {
|
47
|
-
@@in_select=false
|
48
|
-
# @@notifier,@@notified=IO.pipe
|
49
|
-
@@sockets = [] # @@notified]
|
50
|
-
@@timeouts = Hash.new
|
51
|
-
# @@mutex.synchronize do
|
52
|
-
@@query_hash = Hash.new
|
53
|
-
@@socket_hash = Hash.new
|
54
|
-
@@observers = Hash.new
|
55
|
-
@@tick_observers = []
|
56
|
-
@@queued_exceptions=[]
|
57
|
-
@@queued_responses=[]
|
58
|
-
@@queued_validation_responses=[]
|
59
|
-
@@wakeup_sockets = Socket::socketpair(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
|
60
|
-
# end
|
61
|
-
# Now start the select thread
|
62
|
-
@@select_thread = Thread.new {
|
63
|
-
do_select
|
64
|
-
}
|
65
|
-
# # Start the validator thread
|
66
|
-
# @@validator = ValidatorThread.instance
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
|
-
class QuerySettings
|
71
|
-
attr_accessor :query_bytes, :query, :ignore_truncation, :client_queue,
|
72
|
-
:client_query_id, :socket, :dest_server, :dest_port, :endtime, :udp_packet_size,
|
73
|
-
:single_resolver
|
74
|
-
# new(query_bytes, query, ignore_truncation, client_queue, client_query_id,
|
75
|
-
# socket, dest_server, dest_port, endtime, , udp_packet_size, single_resolver)
|
76
|
-
def initialize(*args)
|
77
|
-
@query_bytes = args[0]
|
78
|
-
@query = args[1]
|
79
|
-
@ignore_truncation=args[2]
|
80
|
-
@client_queue = args[3]
|
81
|
-
@client_query_id = args[4]
|
82
|
-
@socket = args[5]
|
83
|
-
@dest_server = args[6]
|
84
|
-
@dest_port=args[7]
|
85
|
-
@endtime = args[8]
|
86
|
-
@udp_packet_size = args[9]
|
87
|
-
@single_resolver = args[10]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def add_to_select(query_settings)
|
92
|
-
# Add the query to sockets, and then wake the select thread up
|
93
|
-
@@mutex.synchronize {
|
94
|
-
check_select_thread_synchronized
|
95
|
-
# @TODO@ This assumes that all client_query_ids are unique!
|
96
|
-
# Would be a good idea at least to check this...
|
97
|
-
@@query_hash[query_settings.client_query_id]=query_settings
|
98
|
-
@@socket_hash[query_settings.socket]=[query_settings.client_query_id] # @todo@ If we use persistent sockets then we need to update this array
|
99
|
-
@@timeouts[query_settings.client_query_id]=query_settings.endtime
|
100
|
-
@@sockets.push(query_settings.socket)
|
101
|
-
}
|
102
|
-
@@wakeup_sockets[0].send("wakeup!", 0)
|
103
|
-
end
|
104
|
-
|
105
|
-
def check_select_thread_synchronized
|
106
|
-
if (!@@select_thread.alive?)
|
107
|
-
Dnsruby.log.debug{"Restarting select thread"}
|
108
|
-
@@select_thread = Thread.new {
|
109
|
-
do_select
|
110
|
-
}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def select_thread_alive?
|
115
|
-
ret=true
|
116
|
-
@@mutex.synchronize{
|
117
|
-
ret = @@select_thread.alive?
|
118
|
-
}
|
119
|
-
return ret
|
120
|
-
end
|
121
|
-
|
122
|
-
def do_select
|
123
|
-
unused_loop_count = 0
|
124
|
-
last_tick_time = Time.now - 10
|
125
|
-
while true do
|
126
|
-
if (last_tick_time < (Time.now - 0.5))
|
127
|
-
send_tick_to_observers # ONLY NEED TO SEND THIS TWICE A SECOND - NOT EVERY SELECT!!!
|
128
|
-
last_tick_time = Time.now
|
129
|
-
end
|
130
|
-
send_queued_exceptions
|
131
|
-
send_queued_responses
|
132
|
-
send_queued_validation_responses
|
133
|
-
timeout = tick_time = 0.1 # We provide a timer service to various Dnsruby classes
|
134
|
-
sockets=[]
|
135
|
-
timeouts=[]
|
136
|
-
has_observer = false
|
137
|
-
@@mutex.synchronize {
|
138
|
-
sockets = @@sockets
|
139
|
-
timeouts = @@timeouts.values
|
140
|
-
has_observer = !@@observers.empty?
|
141
|
-
}
|
142
|
-
sockets << @@wakeup_sockets[1]
|
143
|
-
if (timeouts.length > 0)
|
144
|
-
timeouts.sort!
|
145
|
-
timeout = timeouts[0] - Time.now
|
146
|
-
if (timeout <= 0)
|
147
|
-
process_timeouts
|
148
|
-
timeout = 0
|
149
|
-
next
|
150
|
-
end
|
151
|
-
end
|
152
|
-
ready=nil
|
153
|
-
if (has_observer && (timeout > tick_time))
|
154
|
-
timeout = tick_time
|
155
|
-
end
|
156
|
-
# next if (timeout < 0)
|
157
|
-
begin
|
158
|
-
ready, write, errors = IO.select(sockets, nil, nil, timeout)
|
159
|
-
rescue SelectWakeup
|
160
|
-
# If SelectWakeup, then just restart this loop - the select call will be made with the new data
|
161
|
-
next
|
162
|
-
end
|
163
|
-
if ready && ready.include?(@@wakeup_sockets[1])
|
164
|
-
ready.delete(@@wakeup_sockets[1])
|
165
|
-
wakeup_msg = @@wakeup_sockets[1].recv(20)
|
166
|
-
end
|
167
|
-
if (ready == nil)
|
168
|
-
# proces the timeouts
|
169
|
-
process_timeouts
|
170
|
-
unused_loop_count+=1
|
171
|
-
else
|
172
|
-
process_ready(ready)
|
173
|
-
unused_loop_count=0
|
174
|
-
# process_error(errors)
|
175
|
-
end
|
176
|
-
@@mutex.synchronize{
|
177
|
-
if (unused_loop_count > 10 && @@query_hash.empty? && @@observers.empty?)
|
178
|
-
Dnsruby.log.debug{"Stopping select loop"}
|
179
|
-
return
|
180
|
-
end
|
181
|
-
}
|
182
|
-
# }
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def process_error(errors)
|
187
|
-
Dnsruby.log.debug{"Error! #{errors.inspect}"}
|
188
|
-
# @todo@ Process errors [can we do this in single socket environment?]
|
189
|
-
end
|
190
|
-
|
191
|
-
# @@query_hash[query_settings.client_query_id]=query_settings
|
192
|
-
# @@socket_hash[query_settings.socket]=[query_settings.client_query_id] # @todo@ If we use persistent sockets then we need to update this array
|
193
|
-
def process_ready(ready)
|
194
|
-
ready.each do |socket|
|
195
|
-
query_settings = nil
|
196
|
-
@@mutex.synchronize{
|
197
|
-
# Can do this if we have a query per socket, but not otherwise...
|
198
|
-
c_q_id = @@socket_hash[socket][0] # @todo@ If we use persistent sockets then this won't work
|
199
|
-
query_settings = @@query_hash[c_q_id]
|
200
|
-
}
|
201
|
-
next if !query_settings
|
202
|
-
udp_packet_size = query_settings.udp_packet_size
|
203
|
-
msg, bytes = get_incoming_data(socket, udp_packet_size)
|
204
|
-
if (msg!=nil)
|
205
|
-
# Check that the IP we received from was the IP we sent to!
|
206
|
-
answerip = msg.answerip.downcase
|
207
|
-
answerfrom = msg.answerfrom.downcase
|
208
|
-
dest_server = query_settings.dest_server
|
209
|
-
if (dest_server && (dest_server != '0.0.0.0') &&
|
210
|
-
(answerip != query_settings.dest_server.downcase) &&
|
211
|
-
(answerfrom != query_settings.dest_server.downcase))
|
212
|
-
Dnsruby.log.warn("Unsolicited response received from #{answerip} instead of #{query_settings.dest_server}")
|
213
|
-
else
|
214
|
-
send_response_to_client(msg, bytes, socket)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
ready.delete(socket)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def send_response_to_client(msg, bytes, socket)
|
222
|
-
# Figure out which client_ids we were expecting on this socket, then see if any header ids match up
|
223
|
-
# @TODO@ Can get rid of this, as we only have one query per socket.
|
224
|
-
client_ids=[]
|
225
|
-
@@mutex.synchronize{
|
226
|
-
client_ids = @@socket_hash[socket]
|
227
|
-
}
|
228
|
-
# get the queries associated with them
|
229
|
-
client_ids.each do |id|
|
230
|
-
query_header_id=nil
|
231
|
-
@@mutex.synchronize{
|
232
|
-
query_header_id = @@query_hash[id].query.header.id
|
233
|
-
}
|
234
|
-
if (query_header_id == msg.header.id)
|
235
|
-
# process the response
|
236
|
-
client_queue = nil
|
237
|
-
res = nil
|
238
|
-
query=nil
|
239
|
-
@@mutex.synchronize{
|
240
|
-
client_queue = @@query_hash[id].client_queue
|
241
|
-
res = @@query_hash[id].single_resolver
|
242
|
-
query = @@query_hash[id].query
|
243
|
-
}
|
244
|
-
tcp = (socket.class == TCPSocket)
|
245
|
-
# At this point, we should check if the response is OK
|
246
|
-
if (ret = res.check_response(msg, bytes, query, client_queue, id, tcp))
|
247
|
-
remove_id(id)
|
248
|
-
exception = msg.get_exception
|
249
|
-
if (ret.instance_of?TsigError)
|
250
|
-
exception = ret
|
251
|
-
end
|
252
|
-
Dnsruby.log.debug{"Pushing response to client queue"}
|
253
|
-
push_to_client(id, client_queue, msg, exception, query, res)
|
254
|
-
# client_queue.push([id, msg, exception])
|
255
|
-
# notify_queue_observers(client_queue, id)
|
256
|
-
else
|
257
|
-
# Sending query again - don't return response
|
258
|
-
end
|
259
|
-
return
|
260
|
-
end
|
261
|
-
end
|
262
|
-
# If not, then we have an error
|
263
|
-
Dnsruby.log.error{"Stray packet - " + msg.inspect + "\n from " + socket.inspect}
|
264
|
-
print("Stray packet - " + msg.question()[0].qname.to_s + " from " + msg.answerip.to_s + ", #{client_ids.length} client_ids\n")
|
265
|
-
end
|
266
|
-
|
267
|
-
def remove_id(id)
|
268
|
-
socket=nil
|
269
|
-
@@mutex.synchronize{
|
270
|
-
socket = @@query_hash[id].socket
|
271
|
-
@@timeouts.delete(id)
|
272
|
-
@@query_hash.delete(id)
|
273
|
-
@@socket_hash.delete(socket)
|
274
|
-
@@sockets.delete(socket) # @TODO@ Not if persistent!
|
275
|
-
}
|
276
|
-
Dnsruby.log.debug{"Closing socket #{socket}"}
|
277
|
-
socket.close # @TODO@ Not if persistent!
|
278
|
-
end
|
279
|
-
|
280
|
-
def process_timeouts
|
281
|
-
time_now = Time.now
|
282
|
-
timeouts={}
|
283
|
-
@@mutex.synchronize {
|
284
|
-
timeouts = @@timeouts
|
285
|
-
}
|
286
|
-
timeouts.each do |client_id, timeout|
|
287
|
-
if (timeout < time_now)
|
288
|
-
send_exception_to_client(ResolvTimeout.new("Query timed out"), nil, client_id)
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
def tcp_read(socket, len)
|
294
|
-
buf=""
|
295
|
-
while (buf.length < len) do
|
296
|
-
input = socket.recv(len-buf.length)
|
297
|
-
if (input=="")
|
298
|
-
TheLog.info("Bad response from server - no bytes read - ignoring")
|
299
|
-
return false
|
300
|
-
end
|
301
|
-
buf += input
|
302
|
-
end
|
303
|
-
return buf
|
304
|
-
end
|
305
|
-
|
306
|
-
def get_incoming_data(socket, packet_size)
|
307
|
-
answerfrom,answerip,answerport,answersize=nil
|
308
|
-
ans,buf = nil
|
309
|
-
begin
|
310
|
-
if (socket.class == TCPSocket)
|
311
|
-
# @todo@ Ruby Bug #9061 stops this working right
|
312
|
-
# We'd like to do a socket.recvfrom, but that raises an Exception
|
313
|
-
# on Windows for TCPSocket for Ruby 1.8.5 (and 1.8.6).
|
314
|
-
# So, we need to do something different for TCP than UDP. *sigh*
|
315
|
-
# @TODO@ This workaround will only work if there is exactly one socket per query
|
316
|
-
# - *not* ideal TCP use!
|
317
|
-
@@mutex.synchronize{
|
318
|
-
client_id = @@socket_hash[socket][0]
|
319
|
-
answerfrom = @@query_hash[client_id].dest_server
|
320
|
-
answerip = answerfrom
|
321
|
-
answerport = @@query_hash[client_id].dest_port
|
322
|
-
}
|
323
|
-
buf = tcp_read(socket, 2)
|
324
|
-
if (!buf)
|
325
|
-
handle_recvfrom_failure(socket, "")
|
326
|
-
return
|
327
|
-
end
|
328
|
-
answersize = buf.unpack('n')[0]
|
329
|
-
buf = tcp_read(socket,answersize)
|
330
|
-
if (!buf)
|
331
|
-
handle_recvfrom_failure(socket, "")
|
332
|
-
return
|
333
|
-
end
|
334
|
-
else
|
335
|
-
if (ret = socket.recvfrom(packet_size))
|
336
|
-
buf = ret[0]
|
337
|
-
answerport=ret[1][1]
|
338
|
-
answerfrom=ret[1][2]
|
339
|
-
answerip=ret[1][3]
|
340
|
-
answersize=(buf.length)
|
341
|
-
else
|
342
|
-
# recvfrom failed - why?
|
343
|
-
Dnsruby.log.error{"Error - recvfrom failed from #{socket}"}
|
344
|
-
handle_recvfrom_failure(socket, "")
|
345
|
-
return
|
346
|
-
end
|
347
|
-
end
|
348
|
-
rescue Exception => e
|
349
|
-
Dnsruby.log.error{"Error - recvfrom failed from #{socket}, exception : #{e}"}
|
350
|
-
handle_recvfrom_failure(socket, e)
|
351
|
-
return
|
352
|
-
end
|
353
|
-
Dnsruby.log.debug{";; answer from #{answerfrom} : #{answersize} bytes\n"}
|
354
|
-
|
355
|
-
begin
|
356
|
-
ans = Message.decode(buf)
|
357
|
-
rescue Exception => e
|
358
|
-
# print "DECODE ERROR\n"
|
359
|
-
Dnsruby.log.error{"Decode error! #{e.class}, #{e}\nfor msg (length=#{buf.length}) : #{buf}"}
|
360
|
-
# @TODO@ Should know this from the socket!
|
361
|
-
client_id=get_client_id_from_answerfrom(socket, answerip, answerport)
|
362
|
-
if (client_id != nil)
|
363
|
-
send_exception_to_client(e, socket, client_id)
|
364
|
-
else
|
365
|
-
Dnsruby.log.error{"Decode error from #{answerfrom} but can't determine packet id"}
|
366
|
-
end
|
367
|
-
return
|
368
|
-
end
|
369
|
-
|
370
|
-
if (ans!= nil)
|
371
|
-
Dnsruby.log.debug{"#{ans}"}
|
372
|
-
ans.answerfrom=(answerfrom)
|
373
|
-
ans.answersize=(answersize)
|
374
|
-
ans.answerip =(answerip)
|
375
|
-
end
|
376
|
-
return ans, buf
|
377
|
-
end
|
378
|
-
|
379
|
-
def handle_recvfrom_failure(socket, exception)
|
380
|
-
# No way to notify the client about this error, unless there was only one connection on the socket
|
381
|
-
# Not a problem, as there only will ever be one connection on the socket (Kaminsky attack mitigation)
|
382
|
-
ids_for_socket = []
|
383
|
-
@@mutex.synchronize{
|
384
|
-
ids_for_socket = @@socket_hash[socket]
|
385
|
-
}
|
386
|
-
if (ids_for_socket.length == 1)
|
387
|
-
answerfrom=nil
|
388
|
-
@@mutex.synchronize{
|
389
|
-
query_settings = @@query_hash[ids_for_socket[0]]
|
390
|
-
answerfrom=query_settings.dest_server
|
391
|
-
}
|
392
|
-
send_exception_to_client(OtherResolvError.new("recvfrom failed from #{answerfrom}; #{exception}"), socket, ids_for_socket[0])
|
393
|
-
else
|
394
|
-
Dnsruby.log.fatal{"Recvfrom failed from #{socket}, no way to tell query id"}
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
def get_client_id_from_answerfrom(socket, answerip, answerport)
|
399
|
-
# @TODO@ Can get rid of this, as there is only one query per socket
|
400
|
-
client_id=nil
|
401
|
-
# Figure out client id from answerfrom
|
402
|
-
@@mutex.synchronize{
|
403
|
-
ids = @@socket_hash[socket]
|
404
|
-
ids.each do |id|
|
405
|
-
# Does this id speak to this dest_server?
|
406
|
-
query_settings = @@query_hash[id]
|
407
|
-
if (answerip == query_settings.dest_server && answerport == query_settings.dest_port)
|
408
|
-
# We have a match
|
409
|
-
# - @TODO@ as long as we're not speaking to the same server on two ports!
|
410
|
-
client_id = id
|
411
|
-
break
|
412
|
-
end
|
413
|
-
end
|
414
|
-
}
|
415
|
-
return client_id
|
416
|
-
end
|
417
|
-
|
418
|
-
def send_exception_to_client(err, socket, client_id, msg=nil)
|
419
|
-
# find the client response queue
|
420
|
-
client_queue = nil
|
421
|
-
@@mutex.synchronize {
|
422
|
-
client_queue = @@query_hash[client_id].client_queue
|
423
|
-
}
|
424
|
-
remove_id(client_id)
|
425
|
-
# push_to_client(client_id, client_queue, msg, err)
|
426
|
-
client_queue.push([client_id, Resolver::EventType::ERROR, msg, err])
|
427
|
-
notify_queue_observers(client_queue, client_id)
|
428
|
-
end
|
429
|
-
|
430
|
-
def push_exception_to_select(client_id, client_queue, err, msg)
|
431
|
-
@@mutex.synchronize{
|
432
|
-
@@queued_exceptions.push([client_id, client_queue, err, msg])
|
433
|
-
}
|
434
|
-
# Make sure select loop is running!
|
435
|
-
if (@@select_thread && @@select_thread.alive?)
|
436
|
-
else
|
437
|
-
@@select_thread = Thread.new {
|
438
|
-
do_select
|
439
|
-
}
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
def push_response_to_select(client_id, client_queue, msg, query, res)
|
444
|
-
# This needs to queue the response TO THE SELECT THREAD, which then needs
|
445
|
-
# to send it out from its normal loop.
|
446
|
-
Dnsruby.log.debug{"Pushing response to client queue direct from resolver or validator"}
|
447
|
-
@@mutex.synchronize{
|
448
|
-
@@queued_responses.push([client_id, client_queue, msg, nil, query, res])
|
449
|
-
}
|
450
|
-
# Make sure select loop is running!
|
451
|
-
if (@@select_thread && @@select_thread.alive?)
|
452
|
-
else
|
453
|
-
@@select_thread = Thread.new {
|
454
|
-
do_select
|
455
|
-
}
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
def push_validation_response_to_select(client_id, client_queue, msg, err, query, res)
|
460
|
-
# This needs to queue the response TO THE SELECT THREAD, which then needs
|
461
|
-
# to send it out from its normal loop.
|
462
|
-
Dnsruby.log.debug{"Pushing response to client queue direct from resolver or validator"}
|
463
|
-
@@mutex.synchronize{
|
464
|
-
@@queued_validation_responses.push([client_id, client_queue, msg, err, query, res])
|
465
|
-
}
|
466
|
-
# Make sure select loop is running!
|
467
|
-
if (@@select_thread && @@select_thread.alive?)
|
468
|
-
else
|
469
|
-
@@select_thread = Thread.new {
|
470
|
-
do_select
|
471
|
-
}
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
def send_queued_exceptions
|
476
|
-
exceptions = []
|
477
|
-
@@mutex.synchronize{
|
478
|
-
exceptions = @@queued_exceptions
|
479
|
-
@@queued_exceptions = []
|
480
|
-
}
|
481
|
-
|
482
|
-
exceptions.each do |item|
|
483
|
-
client_id, client_queue, err, msg = item
|
484
|
-
# push_to_client(client_id, client_queue, msg, err)
|
485
|
-
client_queue.push([client_id, Resolver::EventType::ERROR, msg, err])
|
486
|
-
notify_queue_observers(client_queue, client_id)
|
487
|
-
end
|
488
|
-
end
|
489
|
-
|
490
|
-
def send_queued_responses
|
491
|
-
responses = []
|
492
|
-
@@mutex.synchronize{
|
493
|
-
responses = @@queued_responses
|
494
|
-
@@queued_responses = []
|
495
|
-
}
|
496
|
-
|
497
|
-
responses.each do |item|
|
498
|
-
client_id, client_queue, msg, err, query, res = item
|
499
|
-
# push_to_client(client_id, client_queue, msg, err)
|
500
|
-
client_queue.push([client_id, Resolver::EventType::RECEIVED, msg, err])
|
501
|
-
notify_queue_observers(client_queue, client_id)
|
502
|
-
# Do we need to validate this? The response has come from the cache -
|
503
|
-
# validate it only if it has not been validated already
|
504
|
-
# So, if we need to validate it, send it to the validation thread
|
505
|
-
# Otherwise, send VALIDATED to the requester.
|
506
|
-
if (((msg.security_level == Message::SecurityLevel::UNCHECKED) ||
|
507
|
-
(msg.security_level == Message::SecurityLevel::INDETERMINATE)) &&
|
508
|
-
(ValidatorThread.requires_validation?(query, msg, err, res)))
|
509
|
-
validator = ValidatorThread.new(client_id, client_queue, msg, err, query ,self, res)
|
510
|
-
validator.run
|
511
|
-
else
|
512
|
-
PacketSender.cache(query, msg) # The validator won't cache it, so we'd better do it now
|
513
|
-
client_queue.push([client_id, Resolver::EventType::VALIDATED, msg, err])
|
514
|
-
notify_queue_observers(client_queue, client_id)
|
515
|
-
end
|
516
|
-
end
|
517
|
-
end
|
518
|
-
|
519
|
-
def send_queued_validation_responses
|
520
|
-
responses = []
|
521
|
-
@@mutex.synchronize{
|
522
|
-
responses = @@queued_validation_responses
|
523
|
-
@@queued_validation_responses = []
|
524
|
-
}
|
525
|
-
|
526
|
-
responses.each do |item|
|
527
|
-
client_id, client_queue, msg, err, query, res = item
|
528
|
-
# push_to_client(client_id, client_queue, msg, err)
|
529
|
-
client_queue.push([client_id, Resolver::EventType::VALIDATED, msg, err])
|
530
|
-
notify_queue_observers(client_queue, client_id)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
def push_to_client(client_id, client_queue, msg, err, query, res)
|
535
|
-
# @TODO@ Really need to let the client know that we have received a valid response!
|
536
|
-
# Can do that by calling notify_observers here, but with an identifier which
|
537
|
-
# defines the response to be a "Response received - validating. Please stop sending"
|
538
|
-
# type of response.
|
539
|
-
client_queue.push([client_id, Resolver::EventType::RECEIVED, msg, err])
|
540
|
-
notify_queue_observers(client_queue, client_id)
|
541
|
-
|
542
|
-
if (!err || (err.instance_of?(NXDomain)))
|
543
|
-
#
|
544
|
-
# This method now needs to push the response to the validator,
|
545
|
-
# which will then take responsibility for delivering it to the client.
|
546
|
-
# The validator will need access to the queue observers -
|
547
|
-
validator = ValidatorThread.new(client_id, client_queue, msg, err, query ,self, res)
|
548
|
-
validator.run
|
549
|
-
# @@validator.add_to_queue([client_id, client_queue, msg, err, query, self, res])
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
def add_observer(client_queue, observer)
|
554
|
-
@@mutex.synchronize {
|
555
|
-
@@observers[client_queue]=observer
|
556
|
-
check_select_thread_synchronized # Is this really necessary? The client should start the thread by sending a query, really...
|
557
|
-
if (!@@tick_observers.include?observer)
|
558
|
-
@@tick_observers.push(observer)
|
559
|
-
end
|
560
|
-
}
|
561
|
-
end
|
562
|
-
|
563
|
-
def remove_observer(client_queue, observer)
|
564
|
-
@@mutex.synchronize {
|
565
|
-
if (@@observers[client_queue]==observer)
|
566
|
-
# @@observers.delete(observer)
|
567
|
-
@@observers.delete(client_queue)
|
568
|
-
else
|
569
|
-
if (@@observers[client_queue] == nil)
|
570
|
-
end
|
571
|
-
Dnsruby.log.error{"remove_observer called with wrong observer for queue"}
|
572
|
-
raise ArgumentError.new("remove_observer called with wrong observer for queue")
|
573
|
-
end
|
574
|
-
if (!@@observers.values.include?observer)
|
575
|
-
@@tick_observers.delete(observer)
|
576
|
-
end
|
577
|
-
}
|
578
|
-
end
|
579
|
-
|
580
|
-
def notify_queue_observers(client_queue, client_query_id)
|
581
|
-
# If any observers are known for this query queue then notify them
|
582
|
-
observer=nil
|
583
|
-
@@mutex.synchronize {
|
584
|
-
observer = @@observers[client_queue]
|
585
|
-
}
|
586
|
-
if (observer)
|
587
|
-
observer.handle_queue_event(client_queue, client_query_id)
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
def send_tick_to_observers
|
592
|
-
# If any observers are known then send them a tick
|
593
|
-
tick_observers=nil
|
594
|
-
@@mutex.synchronize {
|
595
|
-
tick_observers = @@tick_observers
|
596
|
-
}
|
597
|
-
tick_observers.each do |observer|
|
598
|
-
observer.tick
|
599
|
-
end
|
600
|
-
end
|
601
|
-
end
|
602
|
-
end
|