module net // Addr represents an ip address pub struct Addr { addr C.sockaddr len int pub: saddr string port int } pub fn (a Addr) str() string { return '${a.saddr}:${a.port}' } const ( max_ipv4_addr_len = 16 ) fn new_addr(addr C.sockaddr, _saddr string, _port int) ?Addr { mut saddr := _saddr if saddr == '' { // Convert to string representation buf := []byte{ len: max_ipv4_addr_len, init: 0 } $if windows { res := C.WSAStringToAddress(&addr, SocketFamily.inet, C.NULL, &buf.data, &buf.len) if res == 0 { socket_error(-1)? } } $else { res := C.inet_ntop(SocketFamily.inet, &addr, buf.data, buf.len) if res == 0 { socket_error(-1)? } } saddr = buf.bytestr() } mut port := _port if port == 0 { hport := (&C.sockaddr_in(&addr)).sin_port port = C.ntohs(hport) } return Addr { addr int(sizeof(C.sockaddr)) 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 = family hints.ai_socktype = 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(address.str, sport.str, &hints, &info))? } $else { wrap_error(C.getaddrinfo(address.str, sport.str, &hints, &info)) } return new_addr(*info.ai_addr, address, port) }