583
583
# #
584
584
585
585
struct DNSError <: Exception
586
- host:: AbstractString
586
+ host:: String
587
587
code:: Int32
588
588
end
589
589
@@ -592,81 +592,193 @@ function show(io::IO, err::DNSError)
592
592
" (" , uverrorname (err. code), " )" )
593
593
end
594
594
595
- callback_dict = ObjectIdDict ()
596
-
597
595
function uv_getaddrinfocb (req:: Ptr{Void} , status:: Cint , addrinfo:: Ptr{Void} )
598
- data = ccall (:jl_uv_getaddrinfo_data , Ptr{Void}, (Ptr{Void},), req)
599
- data == C_NULL && return
600
- cb = unsafe_pointer_to_objref (data):: Function
601
- pop! (callback_dict,cb) # using pop forces an error if cb not in callback_dict
602
- if status != 0 || addrinfo == C_NULL
603
- invokelatest (cb, UVError (" uv_getaddrinfocb received an unexpected status code" , status))
604
- else
605
- freeaddrinfo = addrinfo
606
- while addrinfo != C_NULL
607
- sockaddr = ccall (:jl_sockaddr_from_addrinfo , Ptr{Void}, (Ptr{Void},), addrinfo)
608
- if ccall (:jl_sockaddr_is_ip4 , Int32, (Ptr{Void},), sockaddr) == 1
609
- invokelatest (cb, IPv4 (ntoh (ccall (:jl_sockaddr_host4 , UInt32, (Ptr{Void},), sockaddr))))
610
- break
611
- # elseif ccall(:jl_sockaddr_is_ip6, Int32, (Ptr{Void},), sockaddr) == 1
612
- # host = Vector{UInt128}(1)
613
- # scope_id = ccall(:jl_sockaddr_host6, UInt32, (Ptr{Void}, Ptr{UInt128}), sockaddr, host)
614
- # invokelatest(cb, IPv6(ntoh(host[1])))
615
- # break
596
+ data = uv_req_data (req)
597
+ if data != C_NULL
598
+ t = unsafe_pointer_to_objref (data):: Task
599
+ uv_req_set_data (req, C_NULL )
600
+ if status != 0 || addrinfo == C_NULL
601
+ schedule (t, UVError (" getaddrinfocb" , status))
602
+ else
603
+ freeaddrinfo = addrinfo
604
+ addrs = IPAddr[]
605
+ while addrinfo != C_NULL
606
+ sockaddr = ccall (:jl_sockaddr_from_addrinfo , Ptr{Void}, (Ptr{Void},), addrinfo)
607
+ if ccall (:jl_sockaddr_is_ip4 , Int32, (Ptr{Void},), sockaddr) == 1
608
+ ip4addr = ccall (:jl_sockaddr_host4 , UInt32, (Ptr{Void},), sockaddr)
609
+ push! (addrs, IPv4 (ntoh (ip4addr)))
610
+ elseif ccall (:jl_sockaddr_is_ip6 , Int32, (Ptr{Void},), sockaddr) == 1
611
+ ip6addr = Ref {UInt128} ()
612
+ scope_id = ccall (:jl_sockaddr_host6 , UInt32, (Ptr{Void}, Ptr{UInt128}), sockaddr, ip6addr)
613
+ push! (addrs, IPv6 (ntoh (ip6addr[])))
614
+ end
615
+ addrinfo = ccall (:jl_next_from_addrinfo , Ptr{Void}, (Ptr{Void},), addrinfo)
616
616
end
617
- addrinfo = ccall (:jl_next_from_addrinfo , Ptr{Void}, (Ptr{Void},), addrinfo)
617
+ ccall (:uv_freeaddrinfo , Void, (Ptr{Void},), freeaddrinfo)
618
+ schedule (t, addrs)
618
619
end
619
- ccall (:uv_freeaddrinfo , Void, (Ptr{Void},), freeaddrinfo)
620
+ else
621
+ # no owner for this req, safe to just free it
622
+ Libc. free (req)
620
623
end
621
- Libc. free (req)
622
624
nothing
623
625
end
624
626
625
- function getaddrinfo (cb:: Function , host:: String )
627
+ """
628
+ getalladdrinfo(host::AbstractString) -> Vector{IPAddr}
629
+
630
+ Gets all of the IP addresses of the `host`.
631
+ Uses the operating system's underlying getaddrinfo implementation, which may do a DNS lookup.
632
+ """
633
+ function getalladdrinfo (host:: String )
626
634
isascii (host) || error (" non-ASCII hostname: $host " )
627
- callback_dict[cb] = cb
628
- status = ccall (:jl_getaddrinfo , Int32, (Ptr{Void}, Cstring, Ptr{UInt8}, Any, Ptr{Void}),
629
- eventloop (), host, C_NULL , cb, uv_jl_getaddrinfocb:: Ptr{Void} )
630
- if status == UV_EINVAL
631
- throw (ArgumentError (" Invalid uv_getaddrinfo() agument" ))
632
- elseif status in [UV_ENOMEM, UV_ENOBUFS]
633
- throw (OutOfMemoryError ())
634
- elseif status < 0
635
- throw (UVError (" uv_getaddrinfo returned an unexpected error code" , status))
635
+ req = Libc. malloc (_sizeof_uv_getaddrinfo)
636
+ uv_req_set_data (req, C_NULL ) # in case we get interrupted before arriving at the wait call
637
+ status = ccall (:jl_getaddrinfo , Int32, (Ptr{Void}, Ptr{Void}, Cstring, Ptr{Void}, Ptr{Void}),
638
+ eventloop (), req, host, #= service=# C_NULL , uv_jl_getaddrinfocb:: Ptr{Void} )
639
+ if status < 0
640
+ Libc. free (req)
641
+ if status == UV_EINVAL
642
+ throw (ArgumentError (" Invalid getaddrinfo argument" ))
643
+ elseif status == UV_ENOMEM || status == UV_ENOBUFS
644
+ throw (OutOfMemoryError ())
645
+ end
646
+ uv_error (" getaddrinfo" , status)
647
+ end
648
+ ct = current_task ()
649
+ preserve_handle (ct)
650
+ r = try
651
+ uv_req_set_data (req, ct)
652
+ wait ()
653
+ finally
654
+ if uv_req_data (req) != C_NULL
655
+ # req is still alive,
656
+ # so make sure we don't get spurious notifications later
657
+ uv_req_set_data (req, C_NULL )
658
+ ccall (:uv_cancel , Int32, (Ptr{Void},), req) # try to let libuv know we don't care anymore
659
+ else
660
+ # done with req
661
+ Libc. free (req)
662
+ end
663
+ unpreserve_handle (ct)
636
664
end
637
- return nothing
665
+ if isa (r, UVError)
666
+ code = r. code
667
+ if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
668
+ UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
669
+ UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
670
+ UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
671
+ UV_EAI_SOCKTYPE)
672
+ throw (DNSError (host, code))
673
+ elseif code == UV_EAI_MEMORY
674
+ throw (OutOfMemoryError ())
675
+ else
676
+ throw (UVError (" getaddrinfo" , code))
677
+ end
678
+ end
679
+ return r:: Vector{IPAddr}
638
680
end
639
- getaddrinfo (cb :: Function , host:: AbstractString ) = getaddrinfo (cb, String (host))
681
+ getalladdrinfo ( host:: AbstractString ) = getalladdrinfo ( String (host))
640
682
641
683
"""
642
- getaddrinfo (host::AbstractString) -> IPAddr
684
+ getalladdrinfo (host::AbstractString, IPAddr=IPv4 ) -> IPAddr
643
685
644
- Gets the IP address of the `host` (may have to do a DNS lookup)
686
+ Gets the first IP address of the `host` of the specified IPAddr type.
687
+ Uses the operating system's underlying getaddrinfo implementation, which may do a DNS lookup.
645
688
"""
646
- function getaddrinfo (host:: String )
647
- c = Condition ()
648
- getaddrinfo (host) do IP
649
- notify (c,IP)
689
+ function getaddrinfo (host:: String , T:: Type{<:IPAddr} )
690
+ addrs = getalladdrinfo (host)
691
+ for addr in addrs
692
+ if addr isa T
693
+ return addr
694
+ end
695
+ end
696
+ throw (DNSError (host, UV_EAI_NONAME))
697
+ end
698
+ getaddrinfo (host:: AbstractString , T:: Type{<:IPAddr} ) = getaddrinfo (String (host), T)
699
+ getaddrinfo (host:: AbstractString ) = getaddrinfo (String (host), IPv4)
700
+
701
+ function uv_getnameinfocb (req:: Ptr{Void} , status:: Cint , hostname:: Cstring , service:: Cstring )
702
+ data = uv_req_data (req)
703
+ if data != C_NULL
704
+ t = unsafe_pointer_to_objref (data):: Task
705
+ uv_req_set_data (req, C_NULL )
706
+ if status != 0
707
+ schedule (t, UVError (" getnameinfocb" , status))
708
+ else
709
+ schedule (t, unsafe_string (hostname))
710
+ end
711
+ else
712
+ # no owner for this req, safe to just free it
713
+ Libc. free (req)
714
+ end
715
+ nothing
716
+ end
717
+
718
+ """
719
+ getnameinfo(host::IPAddr) -> String
720
+
721
+ Performs a reverse-lookup for IP address to return a hostname and service
722
+ using the operating system's underlying getnameinfo implementation.
723
+ """
724
+ function getnameinfo (address:: Union{IPv4, IPv6} )
725
+ req = Libc. malloc (_sizeof_uv_getnameinfo)
726
+ uv_req_set_data (req, C_NULL ) # in case we get interrupted before arriving at the wait call
727
+ ev = eventloop ()
728
+ port = hton (UInt16 (0 ))
729
+ flags = 0
730
+ uvcb = uv_jl_getnameinfocb:: Ptr{Void}
731
+ status = UV_EINVAL
732
+ if address isa IPv4
733
+ status = ccall (:jl_getnameinfo , Int32, (Ptr{Void}, Ptr{Void}, UInt32, UInt16, Cint, Ptr{Void}),
734
+ ev, req, hton (address. host), port, flags, uvcb)
735
+ elseif address isa IPv6
736
+ status = ccall (:jl_getnameinfo6 , Int32, (Ptr{Void}, Ptr{Void}, Ref{UInt128}, UInt16, Cint, Ptr{Void}),
737
+ ev, req, hton (address. host), port, flags, uvcb)
738
+ end
739
+ if status < 0
740
+ Libc. free (req)
741
+ if status == UV_EINVAL
742
+ throw (ArgumentError (" Invalid getnameinfo argument" ))
743
+ elseif status == UV_ENOMEM || status == UV_ENOBUFS
744
+ throw (OutOfMemoryError ())
745
+ end
746
+ uv_error (" getnameinfo" , status)
747
+ end
748
+ ct = current_task ()
749
+ preserve_handle (ct)
750
+ r = try
751
+ uv_req_set_data (req, ct)
752
+ wait ()
753
+ finally
754
+ if uv_req_data (req) != C_NULL
755
+ # req is still alive,
756
+ # so make sure we don't get spurious notifications later
757
+ uv_req_set_data (req, C_NULL )
758
+ ccall (:uv_cancel , Int32, (Ptr{Void},), req) # try to let libuv know we don't care anymore
759
+ else
760
+ # done with req
761
+ Libc. free (req)
762
+ end
763
+ unpreserve_handle (ct)
650
764
end
651
- r = wait (c)
652
765
if isa (r, UVError)
653
- r = r:: UVError
654
766
code = r. code
655
767
if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
656
768
UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
657
769
UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
658
770
UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
659
771
UV_EAI_SOCKTYPE)
660
- throw (DNSError (host , code))
772
+ throw (DNSError (repr (address) , code))
661
773
elseif code == UV_EAI_MEMORY
662
774
throw (OutOfMemoryError ())
663
775
else
664
- throw (SystemError ( " uv_getaddrinfocb " , - code))
776
+ throw (UVError ( " getnameinfo " , code))
665
777
end
666
778
end
667
- return r:: IPAddr
779
+ return r:: String
668
780
end
669
- getaddrinfo (host :: AbstractString ) = getaddrinfo ( String (host))
781
+
670
782
671
783
const _sizeof_uv_interface_address = ccall (:jl_uv_sizeof_interface_address ,Int32,())
672
784
0 commit comments