// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
let global_ifname_socket : Ref[@fd_util.Fd] = {
let context = "creating global socket object for interface name lookup"
let sock = Ref(
if @event_loop.platform is Linux {
make_udp_socket(IPv4, multicast=false, context~) catch {
err => abort(err.to_string())
}
} else {
@fd_util.invalid_fd
},
)
@event_loop.register_hook(
init=() => {
// In some tests there may be multiple event loops spawned in a single program run,
// ensure the global socket object is valid after the last event loop disposed it
if @event_loop.platform is Linux && !@fd_util.fd_is_valid(sock.val) {
sock.val = make_udp_socket(IPv4, multicast=false, context~)
}
},
exit=() => {
guard @fd_util.fd_is_valid(sock.val) else { }
defer {
sock.val = @fd_util.invalid_fd
}
@fd_util.close(
sock.val,
kind=Socket,
context="closing global socket object for interface name lookup",
)
},
)
sock
}
///|
#borrow(name)
extern "C" fn if_nametoindex_ffi(
global_sock : @fd_util.Fd,
name : @os_string.OsString,
) -> UInt = "moonbitlang_async_if_nametoindex"
///|
extern "C" fn if_indextoname_ffi(
global_sock : @fd_util.Fd,
index : UInt,
) -> @c_buffer.Buffer = "moonbitlang_async_if_indextoname"
///|
#doc(hidden)
#internal(internal, "for internal use only")
pub fn if_nametoindex(name : StringView, context~ : String) -> UInt raise {
let os_name = @os_string.encode(name)
let index = if_nametoindex_ffi(global_ifname_socket.val, os_name)
if index is 0 {
@os_error.check_errno("\{context}: if_nametoindex(\{name.escape()})")
}
index
}
///|
#doc(hidden)
#internal(internal, "for internal use only")
pub fn if_indextoname(index : UInt, context~ : String) -> String raise {
let name = if_indextoname_ffi(global_ifname_socket.val, index)
if name.is_null() {
@os_error.check_errno("\{context}: if_indextoname(\{index})")
}
@os_string.decode(name)
}