Module: EventMachine::DnsCache

Defined in:
lib/em/dns_cache.rb

Defined Under Namespace

Classes: Cache, MxQuery, Request, Socket

Class Method Summary collapse

Class Method Details

.add_cache_entry(cache_type, domain, value, expiration) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/em/dns_cache.rb', line 48

def self.add_cache_entry cache_type, domain, value, expiration
	cache = if cache_type == :mx
		@mx_cache
	elsif cache_type == :a
		@a_cache
	else
		raise "bad cache type"
	end

	v = EM::DefaultDeferrable.new
	v.succeed( value.dup.freeze )
	cache.add domain, v, expiration
end

.add_nameserver(ns) ⇒ Object



39
40
41
# File 'lib/em/dns_cache.rb', line 39

def self.add_nameserver ns
	@nameservers << ns unless @nameservers.include?(ns)
end

.lazy_initializeObject



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/em/dns_cache.rb', line 165

def self.lazy_initialize
	# Will throw an exception if EM is not running.
	# We wire a signaller into the socket handler to tell us when that socket
	# goes away. (Which can happen, among other things, if the reactor
	# stops and restarts.)
	#
	raise "EventMachine reactor not running" unless EM.reactor_running?

	unless @u
		us = proc {@u = nil}
		@u = EM::open_datagram_socket( "0.0.0.0", 0, Socket ) {|c|
			c.unbind_signaller = us
		}
	end

end

.parse_local_mx_records(txt) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/em/dns_cache.rb', line 183

def self.parse_local_mx_records txt
	domain = nil
	addrs = []

	add_it = proc {
		a = addrs.sort {|m,n| m.last <=> n.last}.map {|y| y.first}
		add_cache_entry :mx, domain, a, -1
	}

	txt = StringIO.new( txt ) if txt.is_a?(String)
	txt.each_line {|ln|
		if ln =~ /\A\s*([\d\w\.\-\_]+)\s+(\d+)\s*\Z/
			if domain
				addrs << [$1.dup, $2.dup.to_i]
			end
		elsif ln =~ /\A\s*([^\s\:]+)\s*\:\s*\Z/
			add_it.call if domain
			domain = $1.dup
			addrs.clear
		end
	}

	add_it.call if domain
end

.resolve(domain) ⇒ Object

Needs to be DRYed up with resolve_mx.



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
# File 'lib/em/dns_cache.rb', line 64

def self.resolve domain
	if d = @a_cache.retrieve(domain)
		d
	else
=begin
		d = @a_cache[domain]
		if d.first < Time.now
			$>.puts "Expiring stale cache entry for #{domain}" if @verbose
			@a_cache.delete domain
			resolve domain
		else
			$>.puts "Fulfilled #{domain} from cache" if @verbose
			d.last
		end
	else
=end
		$>.puts "Fulfilling #{domain} from network" if @verbose
		d = EM::DefaultDeferrable.new
		d.timeout(5)
		@a_cache.add domain, d, 300 # Hard-code a 5 minute expiration
		#@a_cache[domain] = [Time.now+120, d] # Hard code a 120-second expiration.

		lazy_initialize
		m = Resolv::DNS::Message.new
		m.rd = 1
		m.add_question domain, Resolv::DNS::Resource::IN::A
		m = m.encode
		@nameservers.each {|ns|
			@message_ix = (@message_ix + 1) % 60000
			Request.new d, @message_ix
			msg = m.dup
			msg[0,2] = [@message_ix].pack("n")
			@u.send_datagram msg, ns, 53
		}

		d.callback {|resp|
			r = []
			resp.each_answer {|name,ttl,data|
				r << data.address.to_s if data.kind_of?(Resolv::DNS::Resource::IN::A)
			}

			# Freeze the array since we'll be keeping it in cache and passing it
			# around to multiple users. And alternative would have been to dup it.
			r.freeze
			d.succeed r
		}


		d
	end
end

.resolve_mx(domain) ⇒ Object

Needs to be DRYed up with resolve.



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
# File 'lib/em/dns_cache.rb', line 119

def self.resolve_mx domain
	if d = @mx_cache.retrieve(domain)
		d
	else
=begin
	if @mx_cache.has_key?(domain)
		d = @mx_cache[domain]
		if d.first < Time.now
			$>.puts "Expiring stale cache entry for #{domain}" if @verbose
			@mx_cache.delete domain
			resolve_mx domain
		else
			$>.puts "Fulfilled #{domain} from cache" if @verbose
			d.last
		end
	else
=end
		$>.puts "Fulfilling #{domain} from network" if @verbose
		d = EM::DefaultDeferrable.new
		d.timeout(5)
		#@mx_cache[domain] = [Time.now+120, d] # Hard code a 120-second expiration.
		@mx_cache.add domain, d, 300 # Hard-code a 5 minute expiration

		mx_query = MxQuery.new d

		lazy_initialize
		m = Resolv::DNS::Message.new
		m.rd = 1
		m.add_question domain, Resolv::DNS::Resource::IN::MX
		m = m.encode
		@nameservers.each {|ns|
			@message_ix = (@message_ix + 1) % 60000
			Request.new mx_query, @message_ix
			msg = m.dup
			msg[0,2] = [@message_ix].pack("n")
			@u.send_datagram msg, ns, 53
		}



		d
	end

end

.verbose(v = true) ⇒ Object



43
44
45
# File 'lib/em/dns_cache.rb', line 43

def self.verbose v=true
	@verbose = v
end