121 lines
3.1 KiB
V
121 lines
3.1 KiB
V
module netio
|
|
|
|
import os
|
|
|
|
#include <netdb.h>
|
|
|
|
fn C.getaddrinfo(&char, &char, &C.addrinfo, &&C.addrinfo) i32
|
|
fn C.freeaddrinfo(&C.addrinfo)
|
|
fn C.getnameinfo(voidptr, i32, &char, i32, &char, i32, i32) i32
|
|
fn C.gai_strerror(i32) &char
|
|
|
|
struct C.addrinfo {
|
|
mut:
|
|
ai_flags i32
|
|
ai_family i32
|
|
ai_socktype i32
|
|
ai_protocol i32
|
|
ai_addrlen i32
|
|
ai_addr voidptr
|
|
ai_canonname voidptr
|
|
ai_next voidptr
|
|
}
|
|
|
|
// AddrInfo represents the [addrinfo](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html) struct.
|
|
pub struct AddrInfo {
|
|
pub:
|
|
flags AddrInfoFlag
|
|
family AddrFamily
|
|
sock_type SocketType
|
|
protocol Protocol
|
|
addr SocketAddr
|
|
canonical string
|
|
}
|
|
|
|
@[params]
|
|
pub struct TranslateAddrParams {
|
|
pub:
|
|
node ?string
|
|
service ?string
|
|
family AddrFamily = af_unspec
|
|
sock_type SocketType
|
|
protocol Protocol
|
|
flags AddrInfoFlag
|
|
}
|
|
|
|
// translate_addr translates the network address. This is a low-level wrapper around
|
|
// the [getaddrinfo(3)](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html) C API.
|
|
pub fn translate_addr(hints TranslateAddrParams) ![]AddrInfo {
|
|
mut hints_ := C.addrinfo{}
|
|
unsafe { vmemset(&hints_, 0, int(sizeof(hints_))) }
|
|
hints_.ai_family = i32(hints.family)
|
|
hints_.ai_socktype = i32(hints.sock_type)
|
|
hints_.ai_protocol = i32(hints.protocol)
|
|
hints_.ai_flags = i32(hints.flags)
|
|
mut node := unsafe { nil }
|
|
if hints.node != none {
|
|
node = &char(hints.node.str)
|
|
}
|
|
mut service := unsafe { nil }
|
|
if hints.service != none {
|
|
service = &char(hints.service.str)
|
|
}
|
|
mut results := &C.addrinfo(unsafe { nil })
|
|
code := C.getaddrinfo(node, service, &hints_, &results)
|
|
if code != 0 {
|
|
if code == C.EAI_SYSTEM {
|
|
return os.last_error()
|
|
}
|
|
msg := C.gai_strerror(code)
|
|
return error_with_code(unsafe { cstring_to_vstring(msg) }, code)
|
|
}
|
|
defer {
|
|
C.freeaddrinfo(results)
|
|
}
|
|
mut addrs := []AddrInfo{}
|
|
for result := unsafe { results }; !isnil(result); result = result.ai_next {
|
|
addrs << AddrInfo{
|
|
flags: int(result.ai_flags)
|
|
family: int(result.ai_family)
|
|
sock_type: int(result.ai_socktype)
|
|
protocol: int(result.ai_protocol)
|
|
addr: unsafe { SocketAddr.from_ptr(result.ai_addr, result.ai_addrlen)! }
|
|
canonical: if isnil(result.ai_canonname) {
|
|
''
|
|
} else {
|
|
unsafe {
|
|
cstring_to_vstring(result.ai_canonname)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return addrs
|
|
}
|
|
|
|
@[params]
|
|
pub struct TranslateNameParams {
|
|
pub:
|
|
flags NameInfoFlag
|
|
}
|
|
|
|
// translate_name does address-to-name translation and returns the host and service names.
|
|
// See [getnameinfo(3)](https://man7.org/linux/man-pages/man3/getnameinfo.3.html) for details.
|
|
pub fn translate_name(sa SocketAddr, params TranslateNameParams) !(string, string) {
|
|
mut addr := []u8{len: C.NI_MAXHOST}
|
|
mut serv := []u8{len: C.NI_MAXSERV}
|
|
code := C.getnameinfo(sa.ptr(), sa.size(), addr.data, addr.len, serv.data, serv.len,
|
|
params.flags)
|
|
if code != 0 {
|
|
if code == C.EAI_SYSTEM {
|
|
return os.last_error()
|
|
}
|
|
msg := C.gai_strerror(code)
|
|
return error_with_code(unsafe { cstring_to_vstring(msg) }, code)
|
|
}
|
|
return unsafe {
|
|
tos_clone(&u8(addr.data))
|
|
}, unsafe {
|
|
tos_clone(&u8(serv.data))
|
|
}
|
|
}
|