• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37932

14 Oct 2024 03:27AM UTC coverage: 86.441% (-1.3%) from 87.739%
#37932

push

local

web-flow
🤖 [master] Bump the Pkg stdlib from fbaa2e337 to 27c1b1ee5 (#56146)

77755 of 89952 relevant lines covered (86.44%)

16248852.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.47
/stdlib/Sockets/src/addrinfo.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    DNSError
5

6
The type of exception thrown when an error occurs in DNS lookup.
7
The `host` field indicates the host URL string.
8
The `code` field indicates the error code based on libuv.
9
"""
10
struct DNSError <: Exception
11
    host::String
1✔
12
    code::Int32
13
end
14

15
function show(io::IO, err::DNSError)
×
16
    print(io, "DNSError: ", err.host, ", ", Base.struverror(err.code),
×
17
                                      " (", Base.uverrorname(err.code), ")")
18
end
19

20
function uv_getaddrinfocb(req::Ptr{Cvoid}, status::Cint, addrinfo::Ptr{Cvoid})
2✔
21
    data = uv_req_data(req)
2✔
22
    if data != C_NULL
2✔
23
        t = unsafe_pointer_to_objref(data)::Task
2✔
24
        uv_req_set_data(req, C_NULL)
2✔
25
        if status != 0 || addrinfo == C_NULL
3✔
26
            schedule(t, _UVError("getaddrinfo", status))
1✔
27
        else
28
            freeaddrinfo = addrinfo
1✔
29
            addrs = IPAddr[]
1✔
30
            while addrinfo != C_NULL
3✔
31
                sockaddr = ccall(:jl_sockaddr_from_addrinfo, Ptr{Cvoid}, (Ptr{Cvoid},), addrinfo)
2✔
32
                if ccall(:jl_sockaddr_is_ip4, Int32, (Ptr{Cvoid},), sockaddr) == 1
2✔
33
                    ip4addr = ccall(:jl_sockaddr_host4, UInt32, (Ptr{Cvoid},), sockaddr)
1✔
34
                    push!(addrs, IPv4(ntoh(ip4addr)))
1✔
35
                elseif ccall(:jl_sockaddr_is_ip6, Int32, (Ptr{Cvoid},), sockaddr) == 1
1✔
36
                    ip6addr = Ref{UInt128}()
1✔
37
                    scope_id = ccall(:jl_sockaddr_host6, UInt32, (Ptr{Cvoid}, Ptr{UInt128}), sockaddr, ip6addr)
1✔
38
                    push!(addrs, IPv6(ntoh(ip6addr[])))
1✔
39
                end
40
                addrinfo = ccall(:jl_next_from_addrinfo, Ptr{Cvoid}, (Ptr{Cvoid},), addrinfo)
2✔
41
            end
2✔
42
            ccall(:uv_freeaddrinfo, Cvoid, (Ptr{Cvoid},), freeaddrinfo)
1✔
43
            schedule(t, addrs)
1✔
44
        end
45
    else
46
        # no owner for this req, safe to just free it
47
        Libc.free(req)
×
48
    end
49
    nothing
2✔
50
end
51

52
"""
53
    getalladdrinfo(host::AbstractString) -> Vector{IPAddr}
54

55
Gets all of the IP addresses of the `host`.
56
Uses the operating system's underlying `getaddrinfo` implementation, which may do a DNS lookup.
57

58
# Examples
59
```julia-repl
60
julia> getalladdrinfo("google.com")
61
2-element Array{IPAddr,1}:
62
 ip"172.217.6.174"
63
 ip"2607:f8b0:4000:804::200e"
64
```
65
"""
66
function getalladdrinfo(host::String)
2✔
67
    req = Libc.malloc(Base._sizeof_uv_getaddrinfo)
2✔
68
    uv_req_set_data(req, C_NULL) # in case we get interrupted before arriving at the wait call
2✔
69
    iolock_begin()
2✔
70
    status = ccall(:jl_getaddrinfo, Int32, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}, Ptr{Cvoid}),
2✔
71
                   eventloop(), req, host, #=service=#C_NULL,
72
                   @cfunction(uv_getaddrinfocb, Cvoid, (Ptr{Cvoid}, Cint, Ptr{Cvoid})))
73
    if status < 0
2✔
74
        Libc.free(req)
×
75
        if status == UV_EINVAL
×
76
            throw(ArgumentError("Invalid getaddrinfo argument"))
×
77
        elseif status == UV_ENOMEM || status == UV_ENOBUFS
×
78
            throw(OutOfMemoryError())
×
79
        end
80
        uv_error("getaddrinfo", status)
×
81
    end
82
    ct = current_task()
2✔
83
    preserve_handle(ct)
2✔
84
    Base.sigatomic_begin()
2✔
85
    uv_req_set_data(req, ct)
2✔
86
    iolock_end()
2✔
87
    r = try
2✔
88
        Base.sigatomic_end()
2✔
89
        wait()
2✔
90
    finally
91
        Base.sigatomic_end()
2✔
92
        iolock_begin()
2✔
93
        q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct)
2✔
94
        if uv_req_data(req) != C_NULL
2✔
95
            # req is still alive,
96
            # so make sure we don't get spurious notifications later
97
            uv_req_set_data(req, C_NULL)
×
98
            ccall(:uv_cancel, Int32, (Ptr{Cvoid},), req) # try to let libuv know we don't care anymore
×
99
        else
100
            # done with req
101
            Libc.free(req)
2✔
102
        end
103
        iolock_end()
2✔
104
        unpreserve_handle(ct)
2✔
105
    end
106
    if isa(r, IOError)
2✔
107
        code = r.code
1✔
108
        if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
2✔
109
                    UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
110
                    UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
111
                    UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
112
                    UV_EAI_SOCKTYPE)
113
            throw(DNSError(host, code))
1✔
114
        elseif code == UV_EAI_MEMORY
×
115
            throw(OutOfMemoryError())
×
116
        else
117
            throw(r)
×
118
        end
119
    end
120
    return r::Vector{IPAddr}
1✔
121
end
122
getalladdrinfo(host::AbstractString) = getalladdrinfo(String(host))
×
123

124
"""
125
    getaddrinfo(host::AbstractString, IPAddr) -> IPAddr
126

127
Gets the first IP address of the `host` of the specified `IPAddr` type.
128
Uses the operating system's underlying getaddrinfo implementation, which may do
129
a DNS lookup.
130

131
# Examples
132
```julia-repl
133
julia> getaddrinfo("localhost", IPv6)
134
ip"::1"
135

136
julia> getaddrinfo("localhost", IPv4)
137
ip"127.0.0.1"
138
```
139
"""
140
function getaddrinfo(host::String, T::Type{<:IPAddr})
×
141
    addrs = getalladdrinfo(host)
×
142
    for addr in addrs
×
143
        if addr isa T
×
144
            return addr
×
145
        end
146
    end
×
147
    throw(DNSError(host, UV_EAI_NONAME))
×
148
end
149
getaddrinfo(host::AbstractString, T::Type{<:IPAddr}) = getaddrinfo(String(host), T)
×
150

151
"""
152
    getaddrinfo(host::AbstractString) -> IPAddr
153

154
Gets the first available IP address of `host`, which may be either an `IPv4` or
155
`IPv6` address. Uses the operating system's underlying getaddrinfo
156
implementation, which may do a DNS lookup.
157
"""
158
function getaddrinfo(host::AbstractString)
159
    addrs = getalladdrinfo(String(host))
2✔
160
    if !isempty(addrs)
1✔
161
        return addrs[begin]::Union{IPv4,IPv6}
1✔
162
    end
163
    throw(DNSError(host, UV_EAI_NONAME))
×
164
end
165

166
function uv_getnameinfocb(req::Ptr{Cvoid}, status::Cint, hostname::Cstring, service::Cstring)
×
167
    data = uv_req_data(req)
×
168
    if data != C_NULL
×
169
        t = unsafe_pointer_to_objref(data)::Task
×
170
        uv_req_set_data(req, C_NULL)
×
171
        if status != 0
×
172
            schedule(t, _UVError("getnameinfo", status))
×
173
        else
174
            schedule(t, unsafe_string(hostname))
×
175
        end
176
    else
177
        # no owner for this req, safe to just free it
178
        Libc.free(req)
×
179
    end
180
    nothing
×
181
end
182

183
"""
184
    getnameinfo(host::IPAddr) -> String
185

186
Performs a reverse-lookup for IP address to return a hostname and service
187
using the operating system's underlying `getnameinfo` implementation.
188

189
# Examples
190
```julia-repl
191
julia> getnameinfo(IPv4("8.8.8.8"))
192
"google-public-dns-a.google.com"
193
```
194
"""
195
function getnameinfo(address::Union{IPv4, IPv6})
×
196
    req = Libc.malloc(Base._sizeof_uv_getnameinfo)
×
197
    uv_req_set_data(req, C_NULL) # in case we get interrupted before arriving at the wait call
×
198
    port = hton(UInt16(0))
×
199
    flags = 0
×
200
    uvcb = @cfunction(uv_getnameinfocb, Cvoid, (Ptr{Cvoid}, Cint, Cstring, Cstring))
×
201
    status = UV_EINVAL
×
202
    host_in = Ref(hton(address.host))
×
203
    iolock_begin()
×
204
    status = ccall(:jl_getnameinfo, Int32, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, UInt16, Cint, Ptr{Cvoid}, Cint),
×
205
                   eventloop(), req, host_in, port, flags, uvcb, address isa IPv6)
206
    if status < 0
×
207
        Libc.free(req)
×
208
        if status == UV_EINVAL
×
209
            throw(ArgumentError("Invalid getnameinfo argument"))
×
210
        elseif status == UV_ENOMEM || status == UV_ENOBUFS
×
211
            throw(OutOfMemoryError())
×
212
        end
213
        uv_error("getnameinfo", status)
×
214
    end
215
    ct = current_task()
×
216
    preserve_handle(ct)
×
217
    Base.sigatomic_begin()
×
218
    uv_req_set_data(req, ct)
×
219
    iolock_end()
×
220
    r = try
×
221
        Base.sigatomic_end()
×
222
        wait()
×
223
    finally
224
        Base.sigatomic_end()
×
225
        iolock_begin()
×
226
        q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct)
×
227
        if uv_req_data(req) != C_NULL
×
228
            # req is still alive,
229
            # so make sure we don't get spurious notifications later
230
            uv_req_set_data(req, C_NULL)
×
231
            ccall(:uv_cancel, Int32, (Ptr{Cvoid},), req) # try to let libuv know we don't care anymore
×
232
        else
233
            # done with req
234
            Libc.free(req)
×
235
        end
236
        iolock_end()
×
237
        unpreserve_handle(ct)
×
238
    end
239
    if isa(r, IOError)
×
240
        code = r.code
×
241
        if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
×
242
                    UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
243
                    UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
244
                    UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
245
                    UV_EAI_SOCKTYPE)
246
            throw(DNSError(repr(address), code))
×
247
        elseif code == UV_EAI_MEMORY
×
248
            throw(OutOfMemoryError())
×
249
        else
250
            throw(r)
×
251
        end
252
    end
253
    return r::String
×
254
end
255

256
const _sizeof_uv_interface_address = ccall(:jl_uv_sizeof_interface_address,Int32,())
257

258
"""
259
    getipaddr() -> IPAddr
260

261
Get an IP address of the local machine, preferring IPv4 over IPv6. Throws if no
262
addresses are available.
263

264
    getipaddr(addr_type::Type{T}) where T<:IPAddr -> T
265

266
Get an IP address of the local machine of the specified type. Throws if no
267
addresses of the specified type are available.
268

269
This function is a backwards-compatibility wrapper around [`getipaddrs`](@ref).
270
New applications should use [`getipaddrs`](@ref) instead.
271

272
# Examples
273
```julia-repl
274
julia> getipaddr()
275
ip"192.168.1.28"
276

277
julia> getipaddr(IPv6)
278
ip"fe80::9731:35af:e1c5:6e49"
279
```
280

281
See also [`getipaddrs`](@ref).
282
"""
283
function getipaddr(addr_type::Type{T}) where T<:IPAddr
284
    addrs = getipaddrs(addr_type)
6✔
285

286
    if length(addrs) == 0
6✔
287
        error("No networking interface available")
×
288
    end
289

290
    # Prefer the first IPv4 address
291
    i = something(findfirst(ip -> ip isa IPv4, addrs), 1)
18✔
292
    return addrs[i]
6✔
293
end
294
getipaddr() = getipaddr(IPv4)
6✔
295

296

297
"""
298
    getipaddrs(addr_type::Type{T}=IPAddr; loopback::Bool=false) where T<:IPAddr -> Vector{T}
299

300
Get the IP addresses of the local machine.
301

302
Setting the optional `addr_type` parameter to `IPv4` or `IPv6` causes only addresses of that type to be returned.
303

304
The `loopback` keyword argument dictates whether loopback addresses (e.g. `ip"127.0.0.1"`, `ip"::1"`) are included.
305

306
!!! compat "Julia 1.2"
307
    This function is available as of Julia 1.2.
308

309
# Examples
310
```julia-repl
311
julia> getipaddrs()
312
5-element Array{IPAddr,1}:
313
 ip"198.51.100.17"
314
 ip"203.0.113.2"
315
 ip"2001:db8:8:4:445e:5fff:fe5d:5500"
316
 ip"2001:db8:8:4:c164:402e:7e3c:3668"
317
 ip"fe80::445e:5fff:fe5d:5500"
318

319
julia> getipaddrs(IPv6)
320
3-element Array{IPv6,1}:
321
 ip"2001:db8:8:4:445e:5fff:fe5d:5500"
322
 ip"2001:db8:8:4:c164:402e:7e3c:3668"
323
 ip"fe80::445e:5fff:fe5d:5500"
324
```
325

326
See also [`islinklocaladdr`](@ref).
327
"""
328
function getipaddrs(addr_type::Type{T}=IPAddr; loopback::Bool=false) where T<:IPAddr
12✔
329
    addresses = T[]
6✔
330
    addr_ref = Ref{Ptr{UInt8}}(C_NULL)
6✔
331
    count_ref = Ref{Int32}(1)
6✔
332
    lo_present = false
6✔
333
    err = ccall(:jl_uv_interface_addresses, Int32, (Ref{Ptr{UInt8}}, Ref{Int32}), addr_ref, count_ref)
6✔
334
    uv_error("getlocalip", err)
6✔
335
    addr, count = addr_ref[], count_ref[]
6✔
336
    for i = 0:(count-1)
6✔
337
        current_addr = addr + i*_sizeof_uv_interface_address
42✔
338
        if 1 == ccall(:jl_uv_interface_address_is_internal, Int32, (Ptr{UInt8},), current_addr)
42✔
339
            lo_present = true
12✔
340
            if !loopback
12✔
341
                continue
12✔
342
            end
343
        end
344
        sockaddr = ccall(:jl_uv_interface_address_sockaddr, Ptr{Cvoid}, (Ptr{UInt8},), current_addr)
30✔
345
        if IPv4 <: T && ccall(:jl_sockaddr_is_ip4, Int32, (Ptr{Cvoid},), sockaddr) == 1
30✔
346
            push!(addresses, IPv4(ntoh(ccall(:jl_sockaddr_host4, UInt32, (Ptr{Cvoid},), sockaddr))))
12✔
347
        elseif IPv6 <: T && ccall(:jl_sockaddr_is_ip6, Int32, (Ptr{Cvoid},), sockaddr) == 1
18✔
348
            addr6 = Ref{UInt128}()
×
349
            scope_id = ccall(:jl_sockaddr_host6, UInt32, (Ptr{Cvoid}, Ref{UInt128},), sockaddr, addr6)
×
350
            push!(addresses, IPv6(ntoh(addr6[])))
×
351
        end
352
    end
78✔
353
    ccall(:uv_free_interface_addresses, Cvoid, (Ptr{UInt8}, Int32), addr, count)
6✔
354
    return addresses
6✔
355
end
356

357
"""
358
    islinklocaladdr(addr::IPAddr)
359

360
Tests if an IP address is a link-local address. Link-local addresses
361
are not guaranteed to be unique beyond their network segment,
362
therefore routers do not forward them. Link-local addresses are from
363
the address blocks `169.254.0.0/16` or `fe80::/10`.
364

365
# Examples
366
```julia
367
filter(!islinklocaladdr, getipaddrs())
368
```
369
"""
370
function islinklocaladdr(addr::IPv4)
×
371
    # RFC 3927
372
    return (addr.host &
×
373
            0xFFFF0000) ==
374
            0xA9FE0000
375
end
376
function islinklocaladdr(addr::IPv6)
×
377
    # RFC 4291
378
    return (addr.host &
×
379
            0xFFC00000000000000000000000000000) ==
380
            0xFE800000000000000000000000000000
381
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc