Skip to content

Commit 31f0743

Browse files
committed
add first working version
1 parent da9906d commit 31f0743

File tree

5 files changed

+299
-0
lines changed

5 files changed

+299
-0
lines changed

Project.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name = "NetworkInterfaces"
2+
uuid = "6f74fd91-2978-43ad-8164-3af8c0ec0142"
3+
authors = ["Johannes Blaschke <[email protected]>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
8+
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"

src/NetworkInterfaces.jl

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
module NetworkInterfaces
2+
using Base: unsafe_convert, RefValue
3+
using Sockets
4+
5+
include("libuv_extensions.jl")
6+
using .LibUVExtensions:
7+
uv_interface_address_t, uv_interface_addresses, uv_free_interface_addresses
8+
9+
10+
const _sizeof_uv_interface_address = ccall(
11+
:jl_uv_sizeof_interface_address, Int32, ()
12+
)
13+
14+
function _next(r::RefValue{Ptr{uv_interface_address_t}})
15+
Ref(
16+
unsafe_convert(
17+
Ptr{uv_interface_address_t},
18+
unsafe_convert(Ptr{UInt8}, r[]) + _sizeof_uv_interface_address
19+
)
20+
)
21+
end
22+
23+
_is_loopback(addr::Ptr{uv_interface_address_t}) = 1 == ccall(
24+
:jl_uv_interface_address_is_internal,
25+
Int32, (Ptr{uv_interface_address_t},),
26+
addr
27+
)
28+
29+
_sockaddr(addr::Ptr{uv_interface_address_t}) = ccall(
30+
:jl_uv_interface_address_sockaddr,
31+
Ptr{Cvoid}, (Ptr{UInt8},),
32+
addr
33+
)
34+
35+
function _iface_name(addr::Ptr{uv_interface_address_t})
36+
r = unsafe_load(addr)
37+
GC.@preserve r unsafe_string(r.name)
38+
end
39+
40+
_sockaddr_is_ip4(sockaddr::Ptr{Cvoid}) = 1 == ccall(
41+
:jl_sockaddr_is_ip4,
42+
Int32, (Ptr{Cvoid},),
43+
sockaddr
44+
)
45+
46+
_sockaddr_is_ip6(sockaddr::Ptr{Cvoid}) = 1 == ccall(
47+
:jl_sockaddr_is_ip6,
48+
Int32, (Ptr{Cvoid},),
49+
sockaddr
50+
)
51+
52+
_sockaddr_to_ip4(sockaddr::Ptr{Cvoid}) = IPv4(
53+
ntoh(ccall(:jl_sockaddr_host4, UInt32, (Ptr{Cvoid},), sockaddr))
54+
)
55+
56+
function _sockaddr_to_ip6(sockaddr::Ptr{Cvoid})
57+
addr6 = Ref{UInt128}()
58+
ccall(
59+
:jl_sockaddr_host6,
60+
UInt32, (Ptr{Cvoid}, Ref{UInt128},),
61+
sockaddr, addr6
62+
)
63+
IPv6(ntoh(addr6[]))
64+
end
65+
66+
struct Interface
67+
name::String
68+
version::Symbol
69+
ip::IPAddr
70+
end
71+
72+
function get_interface_data(
73+
::Type{T}=IPAddr; loopback::Bool=false
74+
) where T <: IPAddr
75+
76+
addr_ref = Ref{Ptr{uv_interface_address_t}}(C_NULL)
77+
count_ref = Ref{Int32}(1)
78+
79+
err = uv_interface_addresses(addr_ref, count_ref)
80+
@assert err == 0
81+
82+
interface_data = Interface[]
83+
current_addr = addr_ref
84+
for i = 0:(count_ref[]-1)
85+
# Skip loopback devices, if so required
86+
if (!loopback) && _is_loopback(current_addr[])
87+
# Don't don't forget to iterate the address pointer though!
88+
current_addr = _next(current_addr)
89+
continue
90+
end
91+
92+
# Interface name string
93+
name = _iface_name(current_addr[])
94+
95+
# Sockaddr used to load IPv4, or IPv6 addresses
96+
sockaddr = _sockaddr(current_addr[])
97+
98+
# Load IP addresses
99+
(ip_type, ip_address) = if IPv4 <: T && _sockaddr_is_ip4(sockaddr)
100+
(:v4, _sockaddr_to_ip4(sockaddr))
101+
elseif IPv6 <: T && _sockaddr_is_ip6(sockaddr)
102+
(:v6, _sockaddr_to_ip6(sockaddr))
103+
else
104+
(:skip, nothing)
105+
end
106+
107+
# Append to data vector and itnerate address pointer
108+
if ip_type != :skip
109+
push!(interface_data, Interface(name, ip_type, ip_address))
110+
end
111+
current_addr = _next(current_addr)
112+
end
113+
114+
uv_free_interface_addresses(addr_ref[], count_ref[])
115+
116+
return interface_data
117+
end
118+
119+
export get_interface_data
120+
121+
end # module NetworkInterfaces

src/generator/generator.jl

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Clang.Generators
2+
using Hwloc.Hwloc_jll
3+
4+
cd(@__DIR__)
5+
6+
include_dir = normpath(@__DIR__, "include")
7+
8+
options = load_options(joinpath(@__DIR__, "generator.toml"))
9+
10+
# Note you must call this function firstly and then append your own flags
11+
args = get_default_args()
12+
push!(args, "-I$include_dir")
13+
14+
headers = [
15+
joinpath(include_dir, header) for header in readdir(include_dir)
16+
if endswith(header, ".h")
17+
]
18+
# # there is also an experimental `detect_headers` function for auto-detecting
19+
# # top-level headers in the directory -- TODO: use this when no-logner
20+
# # experimental:
21+
# headers = detect_headers(clang_dir, args)
22+
23+
# create context
24+
ctx = create_context(headers, args, options)
25+
26+
# run generator
27+
build!(ctx)
28+

src/generator/generator.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[general]
2+
library_name = "libuv"
3+
output_file_path = "libuv.jl"
4+
module_name = "LibUV"
5+
jll_pkg_name = "LibUV_jll"
6+
export_symbol_prefixes = ["uv_"]

src/libuv_extensions.jl

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
module LibUVExtensions
2+
3+
4+
##
5+
#
6+
# These functions are generated from Julia's LibUV
7+
# (https://github.com/libuv/libuv) using Clang.jl -- taking only those functions
8+
# needed by this module
9+
#
10+
# Note: _Some_ of Julia's LibUV prefixes uv_* symbols with jl_*. Eg.:
11+
# uv_interface_addresses becomes: jl_uv_interface_addresses
12+
# (but not all!)
13+
#
14+
##
15+
16+
17+
using CEnum
18+
19+
const sa_family_t = Cushort
20+
21+
const in_port_t = UInt16
22+
23+
const in_addr_t = UInt32
24+
25+
struct in_addr
26+
s_addr::in_addr_t
27+
end
28+
29+
struct sockaddr_in
30+
sin_family::sa_family_t
31+
sin_port::in_port_t
32+
sin_addr::in_addr
33+
sin_zero::NTuple{8, Cuchar}
34+
end
35+
36+
struct sockaddr_in6
37+
data::NTuple{28, UInt8}
38+
end
39+
40+
function Base.getproperty(x::Ptr{sockaddr_in6}, f::Symbol)
41+
f === :sin6_family && return Ptr{sa_family_t}(x + 0)
42+
f === :sin6_port && return Ptr{in_port_t}(x + 2)
43+
f === :sin6_flowinfo && return Ptr{UInt32}(x + 4)
44+
f === :sin6_addr && return Ptr{in6_addr}(x + 8)
45+
f === :sin6_scope_id && return Ptr{UInt32}(x + 24)
46+
return getfield(x, f)
47+
end
48+
49+
function Base.getproperty(x::sockaddr_in6, f::Symbol)
50+
r = Ref{sockaddr_in6}(x)
51+
ptr = Base.unsafe_convert(Ptr{sockaddr_in6}, r)
52+
fptr = getproperty(ptr, f)
53+
GC.@preserve r unsafe_load(fptr)
54+
end
55+
56+
function Base.setproperty!(x::Ptr{sockaddr_in6}, f::Symbol, v)
57+
unsafe_store!(getproperty(x, f), v)
58+
end
59+
60+
struct var"##Ctag#362"
61+
data::NTuple{28, UInt8}
62+
end
63+
64+
function Base.getproperty(x::Ptr{var"##Ctag#362"}, f::Symbol)
65+
f === :address4 && return Ptr{sockaddr_in}(x + 0)
66+
f === :address6 && return Ptr{sockaddr_in6}(x + 0)
67+
return getfield(x, f)
68+
end
69+
70+
function Base.getproperty(x::var"##Ctag#362", f::Symbol)
71+
r = Ref{var"##Ctag#362"}(x)
72+
ptr = Base.unsafe_convert(Ptr{var"##Ctag#362"}, r)
73+
fptr = getproperty(ptr, f)
74+
GC.@preserve r unsafe_load(fptr)
75+
end
76+
77+
function Base.setproperty!(x::Ptr{var"##Ctag#362"}, f::Symbol, v)
78+
unsafe_store!(getproperty(x, f), v)
79+
end
80+
81+
struct var"##Ctag#363"
82+
data::NTuple{28, UInt8}
83+
end
84+
85+
function Base.getproperty(x::Ptr{var"##Ctag#363"}, f::Symbol)
86+
f === :netmask4 && return Ptr{sockaddr_in}(x + 0)
87+
f === :netmask6 && return Ptr{sockaddr_in6}(x + 0)
88+
return getfield(x, f)
89+
end
90+
91+
function Base.getproperty(x::var"##Ctag#363", f::Symbol)
92+
r = Ref{var"##Ctag#363"}(x)
93+
ptr = Base.unsafe_convert(Ptr{var"##Ctag#363"}, r)
94+
fptr = getproperty(ptr, f)
95+
GC.@preserve r unsafe_load(fptr)
96+
end
97+
98+
function Base.setproperty!(x::Ptr{var"##Ctag#363"}, f::Symbol, v)
99+
unsafe_store!(getproperty(x, f), v)
100+
end
101+
102+
struct uv_interface_address_s
103+
data::NTuple{80, UInt8}
104+
end
105+
106+
function Base.getproperty(x::Ptr{uv_interface_address_s}, f::Symbol)
107+
f === :name && return Ptr{Ptr{Cchar}}(x + 0)
108+
f === :phys_addr && return Ptr{NTuple{6, Cchar}}(x + 8)
109+
f === :is_internal && return Ptr{Cint}(x + 16)
110+
f === :address && return Ptr{var"##Ctag#362"}(x + 20)
111+
f === :netmask && return Ptr{var"##Ctag#363"}(x + 48)
112+
return getfield(x, f)
113+
end
114+
115+
function Base.getproperty(x::uv_interface_address_s, f::Symbol)
116+
r = Ref{uv_interface_address_s}(x)
117+
ptr = Base.unsafe_convert(Ptr{uv_interface_address_s}, r)
118+
fptr = getproperty(ptr, f)
119+
GC.@preserve r unsafe_load(fptr)
120+
end
121+
122+
function Base.setproperty!(x::Ptr{uv_interface_address_s}, f::Symbol, v)
123+
unsafe_store!(getproperty(x, f), v)
124+
end
125+
126+
const uv_interface_address_t = uv_interface_address_s
127+
128+
function uv_interface_addresses(addresses, count)
129+
ccall(:jl_uv_interface_addresses, Cint, (Ptr{Ptr{uv_interface_address_t}}, Ptr{Cint}), addresses, count)
130+
end
131+
132+
function uv_free_interface_addresses(addresses, count)
133+
ccall(:uv_free_interface_addresses, Cvoid, (Ptr{uv_interface_address_t}, Cint), addresses, count)
134+
end
135+
136+
end

0 commit comments

Comments
 (0)