aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/net/address.v
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/vlib/net/address.v')
-rw-r--r--v_windows/v/vlib/net/address.v258
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
+}