84 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			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)
 | |
| }
 |