LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style | 1 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 2 // license that can be found in the LICENSE file. |
4 | 3 |
5 // Internet protocol family sockets | 4 // IP sockets |
6 | 5 |
7 package net | 6 package net |
8 | 7 |
9 import "time" | |
10 | |
11 var supportsIPv6, supportsIPv4map bool | |
12 | |
13 func init() { | |
14 sysInit() | |
15 supportsIPv6, supportsIPv4map = probeIPv6Stack() | |
16 } | |
17 | |
18 func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) { | |
19 if filter == nil { | |
20 // We'll take any IP address, but since the dialing code | |
21 // does not yet try multiple addresses, prefer to use | |
22 // an IPv4 address if possible. This is especially relevant | |
23 // if localhost resolves to [ipv6-localhost, ipv4-localhost]. | |
24 // Too much code assumes localhost == ipv4-localhost. | |
25 addr = firstSupportedAddr(ipv4only, addrs) | |
26 if addr == nil { | |
27 addr = firstSupportedAddr(anyaddr, addrs) | |
28 } | |
29 } else { | |
30 addr = firstSupportedAddr(filter, addrs) | |
31 } | |
32 return | |
33 } | |
34 | |
35 func firstSupportedAddr(filter func(IP) IP, addrs []string) IP { | |
36 for _, s := range addrs { | |
37 if addr := filter(ParseIP(s)); addr != nil { | |
38 return addr | |
39 } | |
40 } | |
41 return nil | |
42 } | |
43 | |
44 func anyaddr(x IP) IP { | |
45 if x4 := x.To4(); x4 != nil { | |
46 return x4 | |
47 } | |
48 if supportsIPv6 { | |
49 return x | |
50 } | |
51 return nil | |
52 } | |
53 | |
54 func ipv4only(x IP) IP { return x.To4() } | |
55 | |
56 func ipv6only(x IP) IP { | |
57 // Only return addresses that we can use | |
58 // with the kernel's IPv6 addressing modes. | |
59 if len(x) == IPv6len && x.To4() == nil && supportsIPv6 { | |
60 return x | |
61 } | |
62 return nil | |
63 } | |
64 | |
65 type InvalidAddrError string | |
66 | |
67 func (e InvalidAddrError) Error() string { return string(e) } | |
68 func (e InvalidAddrError) Timeout() bool { return false } | |
69 func (e InvalidAddrError) Temporary() bool { return false } | |
70 | |
71 // SplitHostPort splits a network address of the form | |
72 // "host:port" or "[host]:port" into host and port. | |
73 // The latter form must be used when host contains a colon. | |
74 func SplitHostPort(hostport string) (host, port string, err error) { | |
75 // The port starts after the last colon. | |
76 i := last(hostport, ':') | |
77 if i < 0 { | |
78 err = &AddrError{"missing port in address", hostport} | |
79 return | |
80 } | |
81 | |
82 host, port = hostport[0:i], hostport[i+1:] | |
83 | |
84 // Can put brackets around host ... | |
85 if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { | |
86 host = host[1 : len(host)-1] | |
87 } else { | |
88 // ... but if there are no brackets, no colons. | |
89 if byteIndex(host, ':') >= 0 { | |
90 err = &AddrError{"too many colons in address", hostport} | |
91 return | |
92 } | |
93 } | |
94 return | |
95 } | |
96 | |
97 // JoinHostPort combines host and port into a network address | |
98 // of the form "host:port" or, if host contains a colon, "[host]:port". | |
99 func JoinHostPort(host, port string) string { | |
100 // If host has colons, have to bracket it. | |
101 if byteIndex(host, ':') >= 0 { | |
102 return "[" + host + "]:" + port | |
103 } | |
104 return host + ":" + port | |
105 } | |
106 | |
107 // Convert "host:port" into IP address and port. | |
108 func hostPortToIP(net, hostport string, deadline time.Time) (ip IP, iport int, e
rr error) { | |
109 host, port, err := SplitHostPort(hostport) | |
110 if err != nil { | |
111 return nil, 0, err | |
112 } | |
113 | |
114 var addr IP | |
115 if host != "" { | |
116 // Try as an IP address. | |
117 addr = ParseIP(host) | |
118 if addr == nil { | |
119 var filter func(IP) IP | |
120 if net != "" && net[len(net)-1] == '4' { | |
121 filter = ipv4only | |
122 } | |
123 if net != "" && net[len(net)-1] == '6' { | |
124 filter = ipv6only | |
125 } | |
126 // Not an IP address. Try as a DNS name. | |
127 addrs, err := lookupHostDeadline(host, deadline) | |
128 if err != nil { | |
129 return nil, 0, err | |
130 } | |
131 addr = firstFavoriteAddr(filter, addrs) | |
132 if addr == nil { | |
133 // should not happen | |
134 return nil, 0, &AddrError{"LookupHost returned n
o suitable address", addrs[0]} | |
135 } | |
136 } | |
137 } | |
138 | |
139 p, err := parsePort(net, port) | |
140 if err != nil { | |
141 return nil, 0, err | |
142 } | |
143 | |
144 return addr, p, nil | |
145 } | |
146 | |
147 func zoneIdToString(id int) string { | |
148 if id == 0 { | |
149 return "0" | |
150 } | |
151 if ifi, err := InterfaceByIndex(id); err == nil { | |
152 return ifi.Name | |
153 } | |
154 return itod(uint(id)) | |
155 } | |
156 | |
157 func zoneIdToInt(id string) int { | |
158 if id == "" { | |
159 return 0 | |
160 } | |
161 if ifi, err := InterfaceByName(id); err == nil { | |
162 return ifi.Index | |
163 } | |
164 n, _, _ := dtoi(id, 0) | |
165 return n | |
166 } | |
LEFT | RIGHT |