Index: src/resolver.cr ================================================================== --- src/resolver.cr +++ src/resolver.cr @@ -98,24 +98,48 @@ case used_ns.family when Socket::Family::INET6 if @v6_sock.nil? @v6_sock = s = UDPSocket.new s.bind "::", 0 + start_recv_loop(s) end sock = @v6_sock.not_nil! when Socket::Family::INET if @v4_sock.nil? @v4_sock = s = UDPSocket.new s.bind "0.0.0.0", 0 + start_recv_loop(s) end sock = @v4_sock.not_nil! else raise ArgumentError.new("Nameserver must be INET or INET6") end sock.send(context.raw_data, used_ns) end + + def start_recv_loop(sock : UDPSocket) : Nil + spawn do + buf = Bytes.new(0x10000) + + until sock.closed? + begin + len, addr = sock.receive(buf) + rescue ex : IO::Error + p ex + break if sock.closed? && ex.os_error.nil? + raise ex + end + handle_packet(buf[0, len], addr) + end + end + end + + def handle_packet(packet : Bytes, sender : Socket::IPAddress) + p packet + end def stop : Nil - # TODO + @v6_sock.try { |s| s.close } + @v4_sock.try { |s| s.close } end end end Index: tests/example.cr ================================================================== --- tests/example.cr +++ tests/example.cr @@ -6,5 +6,9 @@ query = AsyncDNS::Query.new("crystal-lang.org", AsyncDNS::DNSClass::IN, AsyncDNS::RRType::A) resolver = AsyncDNS::Resolver.new resolver.resolve(query) { |response| p response } + +sleep 2 +resolver.stop +sleep 2