v2 / vlib / net / address.c.v
347 lines · 309 sloc · 7.34 KB · 5696dc8da95388d0c3906688619582df87628097
Raw
1module net
2
3import io.util
4import net.conv
5import os
6
7union AddrData {
8 Unix
9 Ip
10 Ip6
11}
12
13const addr_ip6_any = [16]u8{init: u8(0)}
14const addr_ip_any = [4]u8{init: u8(0)}
15
16// new_ip6 creates a new Addr from the IP6 address family, based on the given port and addr
17pub fn new_ip6(port u16, addr [16]u8) Addr {
18 n_port := conv.hton16(port)
19 $if macos || freebsd || openbsd || netbsd || dragonfly {
20 a := Addr{
21 len: u8(sizeof(C.sockaddr_in6))
22 f: u8(AddrFamily.ip6)
23 addr: AddrData{
24 Ip6: Ip6{
25 port: n_port
26 }
27 }
28 }
29 unsafe { vmemcpy(&a.addr.Ip6.addr[0], &addr[0], 16) }
30 return a
31 } $else {
32 a := Addr{
33 f: u16(AddrFamily.ip6)
34 addr: AddrData{
35 Ip6: Ip6{
36 port: n_port
37 }
38 }
39 }
40 unsafe { vmemcpy(&a.addr.Ip6.addr[0], &addr[0], 16) }
41 return a
42 }
43}
44
45// new_ip creates a new Addr from the IPv4 address family, based on the given port and addr
46pub fn new_ip(port u16, addr [4]u8) Addr {
47 n_port := conv.hton16(port)
48 $if macos || freebsd || openbsd || netbsd || dragonfly {
49 a := Addr{
50 len: u8(sizeof(C.sockaddr_in))
51 f: u8(AddrFamily.ip)
52 addr: AddrData{
53 Ip: Ip{
54 port: n_port
55 }
56 }
57 }
58 unsafe { vmemcpy(&a.addr.Ip.addr[0], &addr[0], 4) }
59 return a
60 } $else {
61 a := Addr{
62 f: u16(AddrFamily.ip)
63 addr: AddrData{
64 Ip: Ip{
65 port: n_port
66 }
67 }
68 }
69 unsafe { vmemcpy(&a.addr.Ip.addr[0], &addr[0], 4) }
70 return a
71 }
72}
73
74fn temp_unix() !Addr {
75 // create a temp file to get a filename
76 // close it
77 // remove it
78 // then reuse the filename
79 mut file, filename := util.temp_file()!
80 file.close()
81 os.rm(filename)!
82 addrs := resolve_addrs(filename, .unix, .udp)!
83 return addrs[0]
84}
85
86// family returns the family/kind of the given address `a`
87pub fn (a Addr) family() AddrFamily {
88 return unsafe { AddrFamily(a.f) }
89}
90
91// port returns the ip or ip6 port of the given address `a`
92pub fn (a Addr) port() !u16 {
93 match unsafe { AddrFamily(a.f) } {
94 .ip {
95 unsafe {
96 return conv.ntoh16(a.addr.Ip.port)
97 }
98 }
99 .ip6 {
100 unsafe {
101 return conv.ntoh16(a.addr.Ip6.port)
102 }
103 }
104 .unix {
105 return error('unix addr has no port')
106 }
107 .unspec {
108 return error('cannot find port for unspec addr family')
109 }
110 }
111}
112
113const max_ip_len = 24
114const max_ip6_len = 46
115
116// str returns a string representation of `a`
117pub fn (a Ip) str() string {
118 buf := [max_ip_len]char{}
119
120 res := &char(C.inet_ntop(i32(AddrFamily.ip), &a.addr, &buf[0], buf.len))
121
122 if res == 0 {
123 return '<Unknown>'
124 }
125
126 saddr := unsafe { cstring_to_vstring(res) }
127 port := conv.ntoh16(a.port)
128 return '${saddr}:${port}'
129}
130
131// str returns a string representation of `a`. The IPv6 portion is
132// rendered per RFC 5952 by canonical_ipv6_from_bytes (pure V), instead
133// of libc's inet_ntop, which historically emits the deprecated
134// IPv4-compatible mixed form (`::a.b.c.d`) for any address with the
135// upper 96 bits zero.
136pub fn (a Ip6) str() string {
137 saddr := canonical_ipv6_from_bytes(a.addr[..]) or { return '<Unknown>' }
138 port := conv.ntoh16(a.port)
139 return '[${saddr}]:${port}'
140}
141
142const aoffset = __offsetof(Addr, addr)
143
144// len returns the length in bytes of the address `a`, depending on its family
145pub fn (a &Addr) len() u32 {
146 match a.family() {
147 .ip {
148 return sizeof(Ip) + aoffset
149 }
150 .ip6 {
151 return sizeof(Ip6) + aoffset
152 }
153 .unix {
154 return sizeof(Unix) + aoffset
155 }
156 else {
157 panic('Unknown address family')
158 }
159 }
160}
161
162// resolve_addrs converts the given `addr`, `family` and `typ` to a list of addresses
163pub fn resolve_addrs(addr string, family AddrFamily, typ SocketType) ![]Addr {
164 match family {
165 .ip, .ip6, .unspec {
166 return resolve_ipaddrs(addr, family, typ)
167 }
168 .unix {
169 resolved := Unix{}
170
171 if addr.len > max_unix_path {
172 return error('net: resolve_addrs Unix socket address is too long')
173 }
174
175 // Copy the unix path into the address struct
176 unsafe {
177 C.memcpy(&resolved.path, addr.str, addr.len)
178 }
179
180 return [
181 Addr{
182 f: u8(AddrFamily.unix)
183 addr: AddrData{
184 Unix: resolved
185 }
186 },
187 ]
188 }
189 }
190}
191
192// resolve_addrs converts the given `addr` and `typ` to a list of addresses
193pub fn resolve_addrs_fuzzy(addr string, typ SocketType) ![]Addr {
194 if addr.len == 0 {
195 return error('none')
196 }
197
198 // Use a small heuristic to figure out what address family this is
199 // (out of the ones that we support)
200
201 if addr.contains(':') {
202 // Colon is a reserved character in unix paths
203 // so this must be an ip address
204 return resolve_addrs(addr, .unspec, typ)
205 }
206
207 return resolve_addrs(addr, .unix, typ)
208}
209
210fn wrap_getaddrinfo_error(code int) ! {
211 if code == 0 {
212 return
213 }
214 $if windows {
215 socket_error(0 - code)!
216 } $else {
217 if code == C.EAI_SYSTEM {
218 err_code := error_code()
219 return error_with_code('net: getaddrinfo failed: ${os.posix_get_error_msg(err_code)}',
220 err_code)
221 }
222 return error_with_code('net: getaddrinfo failed: ${unsafe { cstring_to_vstring(C.gai_strerror(code)) }}',
223 code)
224 }
225}
226
227// resolve_ipaddrs converts the given `addr`, `family` and `typ` to a list of addresses
228pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr {
229 address, port := split_address(addr)!
230
231 if addr[0] == `:` {
232 match family {
233 .ip6 {
234 return [new_ip6(port, addr_ip6_any)]
235 }
236 .ip, .unspec {
237 return [new_ip(port, addr_ip_any)]
238 }
239 else {}
240 }
241 }
242
243 mut hints := C.addrinfo{
244 // ai_family: int(family)
245 // ai_socktype: int(typ)
246 // ai_flags: C.AI_PASSIVE
247 }
248 unsafe { vmemset(&hints, 0, int(sizeof(hints))) }
249 hints.ai_family = int(family)
250 hints.ai_socktype = int(typ)
251 hints.ai_flags = C.AI_PASSIVE
252
253 results := &C.addrinfo(unsafe { nil })
254
255 sport := '${port}'
256
257 wrap_getaddrinfo_error(C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results))!
258
259 defer {
260 C.freeaddrinfo(results)
261 }
262
263 // Now that we have our linked list of addresses
264 // convert them into an array
265 mut addresses := []Addr{}
266
267 for result := unsafe { results }; !isnil(result); result = result.ai_next {
268 match unsafe { AddrFamily(result.ai_family) } {
269 .ip {
270 new_addr := Addr{
271 addr: AddrData{
272 Ip: Ip{}
273 }
274 }
275 unsafe {
276 C.memcpy(&new_addr, result.ai_addr, result.ai_addrlen)
277 }
278 addresses << new_addr
279 }
280 .ip6 {
281 new_addr := Addr{
282 addr: AddrData{
283 Ip6: Ip6{}
284 }
285 }
286 unsafe {
287 C.memcpy(&new_addr, result.ai_addr, result.ai_addrlen)
288 }
289 addresses << new_addr
290 }
291 else {
292 panic('Unexpected address family ' + result.ai_family.str())
293 }
294 }
295 }
296
297 return addresses
298}
299
300// str returns a string representation of the address `a`
301pub fn (a Addr) str() string {
302 match unsafe { AddrFamily(a.f) } {
303 .ip {
304 unsafe {
305 return a.addr.Ip.str()
306 }
307 }
308 .ip6 {
309 unsafe {
310 return a.addr.Ip6.str()
311 }
312 }
313 .unix {
314 unsafe {
315 return tos_clone(a.addr.Unix.path[0..max_unix_path].data)
316 }
317 }
318 .unspec {
319 return '<.unspec>'
320 }
321 }
322}
323
324// addr_from_socket_handle returns an address, based on the given integer socket `handle`
325pub fn addr_from_socket_handle(handle int) Addr {
326 mut addr := Addr{
327 addr: AddrData{
328 Ip6: Ip6{}
329 }
330 }
331 mut size := sizeof(addr)
332 C.getsockname(handle, voidptr(&addr), &size)
333 return addr
334}
335
336// peer_addr_from_socket_handle retrieves the ip address and port number, given a socket handle
337pub fn peer_addr_from_socket_handle(handle int) !Addr {
338 mut addr := Addr{
339 addr: AddrData{
340 Ip6: Ip6{}
341 }
342 }
343 mut size := sizeof(Addr)
344 socket_error_message(C.getpeername(handle, voidptr(&addr), &size),
345 'peer_addr_from_socket_handle failed')!
346 return addr
347}
348