v/vlib/net/address.v

84 lines
1.7 KiB
V

module net
// Addr represents an ip address
pub struct Addr {
addr C.sockaddr
len int
pub:
saddr string
port int
}
struct C.addrinfo {
}
pub fn (a Addr) str() string {
return '$a.saddr:$a.port'
}
const (
max_ipv4_addr_len = 24
ipv4_addr_size = sizeof(C.sockaddr_in)
)
fn new_addr(addr C.sockaddr) ?Addr {
addr_len := if addr.sa_family == int(SocketFamily.inet) {
sizeof(C.sockaddr)
} else {
// TODO NOOOOOOOOOOOO
0
}
// Convert to string representation
buf := []byte{len: net.max_ipv4_addr_len, init: 0}
$if windows {
res := C.WSAAddressToStringA(&addr, addr_len, C.NULL, buf.data, unsafe { &u32(&buf.len) })
if res != 0 {
socket_error(-1) ?
}
} $else {
res := &char(C.inet_ntop(SocketFamily.inet, &addr, buf.data, buf.len))
if res == 0 {
socket_error(-1) ?
}
}
mut saddr := buf.bytestr()
hport := unsafe { &C.sockaddr_in(&addr) }.sin_port
port := C.ntohs(hport)
$if windows {
// strip the port from the address string
saddr = saddr.split(':')[0]
}
return Addr{addr, int(addr_len), saddr, port}
}
pub fn resolve_addr(addr string, family SocketFamily, typ SocketType) ?Addr {
address, port := split_address(addr) ?
mut hints := C.addrinfo{}
hints.ai_family = int(family)
hints.ai_socktype = int(typ)
hints.ai_flags = C.AI_PASSIVE
hints.ai_protocol = 0
hints.ai_addrlen = 0
hints.ai_canonname = C.NULL
hints.ai_addr = C.NULL
hints.ai_next = C.NULL
info := &C.addrinfo(0)
sport := '$port'
// This might look silly but is recommended by MSDN
$if windows {
socket_error(0 - C.getaddrinfo(&char(address.str), &char(sport.str), &hints,
&info)) ?
} $else {
x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &info)
wrap_error(x) ?
}
return new_addr(*info.ai_addr)
}