Bug #14571 » combined.patch
| lib/resolv.rb (working copy) | ||
|---|---|---|
| 
             def initialize(*nameserver_port) 
   | 
||
| 
               super() 
   | 
||
| 
               @nameserver_port = nameserver_port 
   | 
||
| 
               @socks_hash = {} 
   | 
||
| 
               @socks = [] 
   | 
||
| 
               nameserver_port.each {|host, port| 
   | 
||
| 
                 if host.index(':') 
   | 
||
| 
                   bind_host = "::" 
   | 
||
| 
                   af = Socket::AF_INET6 
   | 
||
| 
                 else 
   | 
||
| 
                   bind_host = "0.0.0.0" 
   | 
||
| 
                   af = Socket::AF_INET 
   | 
||
| 
                 end 
   | 
||
| 
                 next if @socks_hash[bind_host] 
   | 
||
| 
                 begin 
   | 
||
| 
                   sock = UDPSocket.new(af) 
   | 
||
| 
                 rescue Errno::EAFNOSUPPORT 
   | 
||
| 
                   next # The kernel doesn't support the address family. 
   | 
||
| 
                 end 
   | 
||
| 
                 sock.do_not_reverse_lookup = true 
   | 
||
| 
                 DNS.bind_random_port(sock, bind_host) 
   | 
||
| 
                 @socks << sock 
   | 
||
| 
                 @socks_hash[bind_host] = sock 
   | 
||
| 
               @initialized = false 
   | 
||
| 
               @mutex = Thread::Mutex.new 
   | 
||
| 
             end 
   | 
||
| 
             def lazy_initialize 
   | 
||
| 
               @mutex.synchronize { 
   | 
||
| 
                 next if @initialized 
   | 
||
| 
                 @initialized = true 
   | 
||
| 
                 @socks_hash = {} 
   | 
||
| 
                 @socks = [] 
   | 
||
| 
                 @nameserver_port.each {|host, port| 
   | 
||
| 
                   if host.index(':') 
   | 
||
| 
                     bind_host = "::" 
   | 
||
| 
                     af = Socket::AF_INET6 
   | 
||
| 
                   else 
   | 
||
| 
                     bind_host = "0.0.0.0" 
   | 
||
| 
                     af = Socket::AF_INET 
   | 
||
| 
                   end 
   | 
||
| 
                   next if @socks_hash[bind_host] 
   | 
||
| 
                   begin 
   | 
||
| 
                     sock = UDPSocket.new(af) 
   | 
||
| 
                   rescue Errno::EAFNOSUPPORT 
   | 
||
| 
                     next # The kernel doesn't support the address family. 
   | 
||
| 
                   end 
   | 
||
| 
                   @socks << sock 
   | 
||
| 
                   @socks_hash[bind_host] = sock 
   | 
||
| 
                   sock.do_not_reverse_lookup = true 
   | 
||
| 
                   DNS.bind_random_port(sock, bind_host) 
   | 
||
| 
                 } 
   | 
||
| 
               } 
   | 
||
| 
               self 
   | 
||
| 
             end 
   | 
||
| 
             def recv_reply(readable_socks) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               reply, from = readable_socks[0].recvfrom(UDPSize) 
   | 
||
| 
               return reply, [from[3],from[1]] 
   | 
||
| 
             end 
   | 
||
| 
             def sender(msg, data, host, port=Port) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"] 
   | 
||
| 
               return nil if !sock 
   | 
||
| 
               service = [host, port] 
   | 
||
| ... | ... | |
| 
             end 
   | 
||
| 
             def close 
   | 
||
| 
               super 
   | 
||
| 
               @senders.each_key {|service, id| 
   | 
||
| 
                 DNS.free_request_id(service[0], service[1], id) 
   | 
||
| 
               @mutex.synchronize { 
   | 
||
| 
                 if @initialized 
   | 
||
| 
                   super 
   | 
||
| 
                   @senders.each_key {|service, id| 
   | 
||
| 
                     DNS.free_request_id(service[0], service[1], id) 
   | 
||
| 
                   } 
   | 
||
| 
                   @initialized = false 
   | 
||
| 
                 end 
   | 
||
| 
               } 
   | 
||
| 
             end 
   | 
||
| ... | ... | |
| 
               super() 
   | 
||
| 
               @host = host 
   | 
||
| 
               @port = port 
   | 
||
| 
               is_ipv6 = host.index(':') 
   | 
||
| 
               sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) 
   | 
||
| 
               @socks = [sock] 
   | 
||
| 
               sock.do_not_reverse_lookup = true 
   | 
||
| 
               DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0") 
   | 
||
| 
               sock.connect(host, port) 
   | 
||
| 
               @mutex = Thread::Mutex.new 
   | 
||
| 
               @initialized = false 
   | 
||
| 
             end 
   | 
||
| 
             def lazy_initialize 
   | 
||
| 
               @mutex.synchronize { 
   | 
||
| 
                 next if @initialized 
   | 
||
| 
                 @initialized = true 
   | 
||
| 
                 is_ipv6 = @host.index(':') 
   | 
||
| 
                 sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET) 
   | 
||
| 
                 @socks = [sock] 
   | 
||
| 
                 sock.do_not_reverse_lookup = true 
   | 
||
| 
                 DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0") 
   | 
||
| 
                 sock.connect(@host, @port) 
   | 
||
| 
               } 
   | 
||
| 
               self 
   | 
||
| 
             end 
   | 
||
| 
             def recv_reply(readable_socks) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               reply = readable_socks[0].recv(UDPSize) 
   | 
||
| 
               return reply, nil 
   | 
||
| 
             end 
   | 
||
| 
             def sender(msg, data, host=@host, port=@port) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               unless host == @host && port == @port 
   | 
||
| 
                 raise RequestError.new("host/port don't match: #{host}:#{port}") 
   | 
||
| 
               end 
   | 
||
| ... | ... | |
| 
             end 
   | 
||
| 
             def close 
   | 
||
| 
               super 
   | 
||
| 
               @senders.each_key {|from, id| 
   | 
||
| 
                 DNS.free_request_id(@host, @port, id) 
   | 
||
| 
               } 
   | 
||
| 
               @mutex.synchronize do 
   | 
||
| 
                 if @initialized 
   | 
||
| 
                   super 
   | 
||
| 
                   @senders.each_key {|from, id| 
   | 
||
| 
                     DNS.free_request_id(@host, @port, id) 
   | 
||
| 
                   } 
   | 
||
| 
                   @initialized = false 
   | 
||
| 
                 end 
   | 
||
| 
               end 
   | 
||
| 
             end 
   | 
||
| 
             class Sender < Requester::Sender # :nodoc: 
   | 
||
| ... | ... | |
| 
           class MDNSOneShot < UnconnectedUDP # :nodoc: 
   | 
||
| 
             def sender(msg, data, host, port=Port) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               id = DNS.allocate_request_id(host, port) 
   | 
||
| 
               request = msg.encode 
   | 
||
| 
               request[0,2] = [id].pack('n') 
   | 
||
| ... | ... | |
| 
             end 
   | 
||
| 
             def sender_for(addr, msg) 
   | 
||
| 
               lazy_initialize 
   | 
||
| 
               @senders[msg.id] 
   | 
||
| 
             end 
   | 
||
| 
           end 
   | 
||
| test/resolv/test_dns.rb (working copy) | ||
|---|---|---|
| 
     require 'resolv' 
   | 
||
| 
     require 'socket' 
   | 
||
| 
     require 'tempfile' 
   | 
||
| 
     require 'timeout' 
   | 
||
| 
     require 'minitest/mock' 
   | 
||
| 
     class TestResolvDNS < Test::Unit::TestCase 
   | 
||
| 
       def setup 
   | 
||
| ... | ... | |
| 
         } 
   | 
||
| 
         assert_operator(2**14, :<, m.to_s.length) 
   | 
||
| 
       end 
   | 
||
| 
       def test_timeout_without_leaking_file_descriptors_connected 
   | 
||
| 
         socket = nil 
   | 
||
| 
         bind_random_port = lambda do |udpsock, bind_host="0.0.0.0"| 
   | 
||
| 
           socket = udpsock 
   | 
||
| 
           sleep 3 
   | 
||
| 
         end 
   | 
||
| 
         Resolv::DNS.stub(:bind_random_port, bind_random_port) do 
   | 
||
| 
           r = Resolv::DNS.new(nameserver_port: [['127.0.0.1', 53]]) 
   | 
||
| 
           begin 
   | 
||
| 
             Timeout.timeout(0.5) { r.getname("8.8.8.8") } 
   | 
||
| 
           rescue Timeout::Error 
   | 
||
| 
           end 
   | 
||
| 
         end 
   | 
||
| 
         assert(socket.closed?, "file descriptor leaked") 
   | 
||
| 
       end 
   | 
||
| 
       def test_timeout_without_leaking_file_descriptors_unconnected 
   | 
||
| 
         socket = nil 
   | 
||
| 
         bind_random_port = lambda do |udpsock, bind_host="0.0.0.0"| 
   | 
||
| 
           socket = udpsock 
   | 
||
| 
           sleep 3 
   | 
||
| 
         end 
   | 
||
| 
         Resolv::DNS.stub(:bind_random_port, bind_random_port) do 
   | 
||
| 
           r = Resolv::DNS.new 
   | 
||
| 
           begin 
   | 
||
| 
             Timeout.timeout(0.5) { r.getname("8.8.8.8") } 
   | 
||
| 
           rescue Timeout::Error 
   | 
||
| 
           end 
   | 
||
| 
         end 
   | 
||
| 
         assert(socket.closed?, "file descriptor leaked") 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
- « Previous
 - 1
 - 2
 - 3
 - Next »