From: Stephane D'Alu Date: 2002-07-22T18:25:55+09:00 Subject: [PATCH] resolv.rb The patch is for ruby-1.7.2.2002.07.15: - it fixes the TCP Requester, even if not directly used by the DNS class, some programs may want to use it (for example to perform tests on a DNS server) - add fields 'aa' (authoritative anwser), 'ttl', and 'rec' (recursive) to the Resource class, so that people using Resolv::DNS#getresources can easily access (without redefining several internal methods) the context in which the Resource is to be used (for example a program may want to consider differently the address of a host, if the anwser was emitted from an authoritative server or not). But these 3 fields are more informative and are not taken into account for Resource comparison. can someone commit this patch, if everybody agree of course. --- /usr/local/lib/ruby/1.7/resolv.rb Fri Jul 19 19:37:07 2002 +++ resolv.rb Mon Jul 22 00:17:58 2002 @@ -651,35 +651,44 @@ super() @host = host @port = port - @sock = TCPSocket.new - @sock.connect(host, port) - @sock.fcntl(Fcntl::F_SETFD, 1) @id = -1 @senders = {} - @thread = Thread.new { - DNSThreadGroup.add Thread.current - loop { - len = @sock.read(2).unpack('n') - reply = @sock.read(len) - msg = begin - Message.decode(reply) - rescue DecodeError - STDERR.print("DNS message decoding error: #{reply.inspect}") - next - end - if s = @senders[msg.id] - s.push msg - else - #STDERR.print("non-handled DNS message: #{msg.inspect}") - end - } - } - end + @sock = nil + @mutex = Mutex.new + end + + def lazy_initialize + @mutex.synchronize { + if @sock.nil? + @sock = TCPSocket.new(@host, @port) + @sock.fcntl(Fcntl::F_SETFD, 1) + @thread = Thread.new { + DNSThreadGroup.add Thread.current + loop { + len = @sock.read(2).unpack('n')[0] + reply = @sock.read(len) + msg = begin + Message.decode(reply) + rescue DecodeError + STDERR.print("DNS message decoding error: #{reply.inspect}") + next + end + if s = @senders[msg.id] + s.recv msg + else + #STDERR.print("non-handled DNS message: #{msg.inspect}") + end + } + } + end + } + end def sender(msg, data, queue, host=@host, port=@port) unless host == @host && port == @port raise RequestError.new("host/port don't match: #{host}:#{port}") end + lazy_initialize id = Thread.exclusive { @id = (@id + 1) & 0xffff } request = msg.encode request[0,2] = [request.length, id].pack('nn') @@ -688,7 +697,7 @@ class Sender < Requester::Sender def send - @sock.print(@msg) + @sock.write(@msg) @sock.flush end end @@ -978,6 +987,8 @@ end def add_answer(name, ttl, data) + data.aa = @aa != 0 ? true : false + data.rec = @ra != 0 ? true : false @answer << [Name.create(name), ttl, data] end @@ -988,6 +999,8 @@ end def add_authority(name, ttl, data) + data.aa = @aa != 0 ? true : false + data.rec = @ra != 0 ? true : false @authority << [Name.create(name), ttl, data] end @@ -998,6 +1011,8 @@ end def add_additional(name, ttl, data) + data.aa = @aa != 0 ? true : false + data.rec = @ra != 0 ? true : false @additional << [Name.create(name), ttl, data] end @@ -1232,7 +1247,9 @@ name = self.get_name type, klass, ttl = self.get_unpack('nnN') typeclass = Resource.get_class(type, klass) - return name, ttl, self.get_length16 {typeclass.decode_rdata(self)} + data = self.get_length16 {typeclass.decode_rdata(self)} + data.ttl = ttl + return name, ttl, data end end end @@ -1250,6 +1267,9 @@ class Resource < Query ClassHash = {} + attr_reader :ttl, :aa, :rec + attr_writer :ttl, :aa, :rec + def encode_rdata(msg) raise NotImplementedError.new end @@ -1259,10 +1279,23 @@ end def ==(other) - return self.type == other.type && - self.instance_variables == other.instance_variables && - self.instance_variables.collect {|name| self.instance_eval name} == - other.instance_variables.collect {|name| other.instance_eval name} + return false unless self.type == other.type + siv = self.instance_variables.delete_if {|n| + case n + when "ttl", "aa", "rec" then true + else false + end + } + oiv = other.instance_variables.delete_if {|n| + case n + when "ttl", "aa", "rec" then true + else false + end + } + + return siv == oiv && + siv.collect {|name| self.instance_eval name} == + oiv.collect {|name| other.instance_eval name} end def eql?(other)