This commit is contained in:
ge
2026-04-12 16:30:28 +03:00
parent 5b56659d21
commit 2d2281b8cc
26 changed files with 1002 additions and 640 deletions
+7 -100
View File
@@ -1,24 +1,6 @@
module netio
import encoding.binary
import os
#include <netdb.h>
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
}
fn C.getaddrinfo(&char, &char, &C.addrinfo, &&C.addrinfo) i32
fn C.freeaddrinfo(&C.addrinfo)
// max_unix_path_size value is used to pad the sockaddr_un struct.
const max_unix_path_size = $if linux {
@@ -29,83 +11,6 @@ const max_unix_path_size = $if linux {
104
}
// AddrInfo represents the [addrinfo](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html).
pub struct AddrInfo {
pub:
flags int
family AddrFamily
sock_type SocketType
protocol Protocol
addr SocketAddr
canonical string
}
@[params]
pub struct TranslateAddrHints {
pub:
node ?string
service ?string
family AddrFamily = af_unspec
sock_type SocketType
protocol Protocol
flags int
}
// 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.
// Example:
// ```v
// import os
// import netio
//
// // Resolve the host FQND
// addr_info := netio.translate_addr(node: os.hostname()!, flags: ai_canonname)!
// for addr in addr_info {
// println(addr.canonical)
// }
// ```
pub fn translate_addr(hints TranslateAddrHints) ![]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 })
if C.getaddrinfo(node, service, &hints_, &results) == -1 {
return os.last_error()
}
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
}
// SocketAddr.ipv4 creates new AF_INET socket address.
// addr must be set in network (big-endian) byte order.
pub fn SocketAddr.ipv4(addr [4]u8, port u16) SocketAddr {
@@ -149,9 +54,6 @@ pub fn SocketAddr.unix(path string) !SocketAddr {
// the address itself, you need to do that manually. The benefit is that you can create the
// any kind of socket address.
//
// Note: This function sets the address family struct field for you, it is always first
// and 2-byte size (`u16` type).
//
// SocketAddr is a "constructor" for
// [sockaddr(3type)](https://www.man7.org/linux/man-pages/man3/sockaddr.3type.html) objects.
// Use this function only if you understand what you do. You must manually write the data
@@ -169,7 +71,7 @@ pub fn SocketAddr.unix(path string) !SocketAddr {
// Data must be padded to sockaddr struct size which is 16 bytes. Each field is then
// written in turn, from top to bottom. Keep in mind that two-byte address family field
// (sin_family in this case) is already written. According to the manual page, the
// address and port are written using the network (big endian) byte order.
// address and port are written using the network (big-endian) byte order.
//
// Example:
// ```v
@@ -194,6 +96,7 @@ pub fn SocketAddr.unix(path string) !SocketAddr {
// sa.push(binary.big_endian_get_u16(u16(1080)))!
// sa.push([u8(127), 0, 0, 1])!
// }
// println(sa)
// ```
@[unsafe]
pub fn SocketAddr.new(af AddrFamily, size isize) SocketAddr {
@@ -276,6 +179,10 @@ pub fn (a SocketAddr) u8_array() []u8 {
}
// str returns the string representation of socket address.
// Supported address families are AF_INET, AF_INET6, and AF_UNIX.
// For others a string like 'SocketAddr(0x00000000)' will be returned.
// Examples: '172.16.16.132:1080', '[fdf1:72d1:0033:0000:0000:0000:0000:0247]:25535,
// '/run/app.sock'. See also `translate_name()`.
pub fn (a SocketAddr) str() string {
match a.family() {
af_inet {
@@ -320,7 +227,7 @@ pub fn (a SocketAddr) str() string {
return res
}
else {
return 'SocketAddr(${a.data.str()})'
return 'SocketAddr(0x${a.data:08x})'
}
}
}