diff options
Diffstat (limited to 'v_windows/v/vlib/net/address.v')
-rw-r--r-- | v_windows/v/vlib/net/address.v | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/v_windows/v/vlib/net/address.v b/v_windows/v/vlib/net/address.v new file mode 100644 index 0000000..af1a000 --- /dev/null +++ b/v_windows/v/vlib/net/address.v @@ -0,0 +1,258 @@ +module net + +import io.util +import os + +union AddrData { + Unix + Ip + Ip6 +} + +const ( + addr_ip6_any = [16]byte{init: byte(0)} + addr_ip_any = [4]byte{init: byte(0)} +) + +fn new_ip6(port u16, addr [16]byte) Addr { + a := Addr{ + f: u16(AddrFamily.ip6) + addr: AddrData{ + Ip6: Ip6{ + port: u16(C.htons(port)) + } + } + } + + copy(a.addr.Ip6.addr[0..], addr[0..]) + + return a +} + +fn new_ip(port u16, addr [4]byte) Addr { + a := Addr{ + f: u16(AddrFamily.ip) + addr: AddrData{ + Ip: Ip{ + port: u16(C.htons(port)) + } + } + } + + copy(a.addr.Ip6.addr[0..], addr[0..]) + + return a +} + +fn temp_unix() ?Addr { + // create a temp file to get a filename + // close it + // remove it + // then reuse the filename + mut file, filename := util.temp_file() ? + file.close() + os.rm(filename) ? + addrs := resolve_addrs(filename, .unix, .udp) ? + return addrs[0] +} + +pub fn (a Addr) family() AddrFamily { + return AddrFamily(a.f) +} + +const ( + max_ip_len = 24 + max_ip6_len = 46 +) + +fn (a Ip) str() string { + buf := []byte{len: net.max_ip_len, init: 0} + + res := &char(C.inet_ntop(.ip, &a.addr, buf.data, buf.len)) + + if res == 0 { + return '<Unknown>' + } + + saddr := buf.bytestr() + port := C.ntohs(a.port) + + return '$saddr:$port' +} + +fn (a Ip6) str() string { + buf := []byte{len: net.max_ip6_len, init: 0} + + res := &char(C.inet_ntop(.ip6, &a.addr, buf.data, buf.len)) + + if res == 0 { + return '<Unknown>' + } + + saddr := buf.bytestr() + port := C.ntohs(a.port) + + return '[$saddr]:$port' +} + +const aoffset = __offsetof(Addr, addr) + +fn (a Addr) len() u32 { + match a.family() { + .ip { + return sizeof(Ip) + net.aoffset + } + .ip6 { + return sizeof(Ip6) + net.aoffset + } + .unix { + return sizeof(Unix) + net.aoffset + } + else { + panic('Unknown address family') + } + } +} + +pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ?[]Addr { + match family { + .ip, .ip6, .unspec { + return resolve_ipaddrs(addr, family, @type) + } + .unix { + resolved := Unix{} + + if addr.len > max_unix_path { + return error('net: resolve_addrs Unix socket address is too long') + } + + // Copy the unix path into the address struct + unsafe { + C.memcpy(&resolved.path, addr.str, addr.len) + } + + return [Addr{ + f: u16(AddrFamily.unix) + addr: AddrData{ + Unix: resolved + } + }] + } + } +} + +pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ?[]Addr { + if addr.len == 0 { + return none + } + + // Use a small heuristic to figure out what address family this is + // (out of the ones that we support) + + if addr.contains(':') { + // Colon is a reserved character in unix paths + // so this must be an ip address + return resolve_addrs(addr, .unspec, @type) + } + + return resolve_addrs(addr, .unix, @type) +} + +pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ?[]Addr { + address, port := split_address(addr) ? + + if addr[0] == `:` { + // Use in6addr_any + return [new_ip6(port, net.addr_ip6_any)] + } + + mut hints := C.addrinfo{ + // ai_family: int(family) + // ai_socktype: int(typ) + // ai_flags: C.AI_PASSIVE + } + 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_addr = voidptr(0) + hints.ai_canonname = voidptr(0) + hints.ai_next = voidptr(0) + results := &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, &results)) ? + } $else { + x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results) + wrap_error(x) ? + } + + defer { + C.freeaddrinfo(results) + } + + // Now that we have our linked list of addresses + // convert them into an array + mut addresses := []Addr{} + + for result := results; !isnil(result); result = result.ai_next { + match AddrFamily(result.ai_family) { + .ip, .ip6 { + new_addr := Addr{ + addr: AddrData{ + Ip6: Ip6{} + } + } + unsafe { + C.memcpy(&new_addr, result.ai_addr, result.ai_addrlen) + } + addresses << new_addr + } + else { + panic('Unexpected address family $result.ai_family') + } + } + } + + return addresses +} + +fn (a Addr) str() string { + match AddrFamily(a.f) { + .ip { + unsafe { + return a.addr.Ip.str() + } + } + .ip6 { + unsafe { + return a.addr.Ip6.str() + } + } + .unix { + unsafe { + return tos_clone(a.addr.Unix.path[0..max_unix_path].data) + } + } + .unspec { + return '<.unspec>' + } + } +} + +pub fn addr_from_socket_handle(handle int) Addr { + addr := Addr{ + addr: AddrData{ + Ip6: Ip6{} + } + } + size := sizeof(addr) + + C.getsockname(handle, voidptr(&addr), &size) + + return addr +} |