1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Internet protocol family sockets
11 var supportsIPv6
, supportsIPv4map
bool
15 supportsIPv6
, supportsIPv4map
= probeIPv6Stack()
18 func firstFavoriteAddr(filter
func(IP
) IP
, addrs
[]string) (addr IP
) {
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
)
27 addr
= firstSupportedAddr(anyaddr
, addrs
)
30 addr
= firstSupportedAddr(filter
, addrs
)
35 func firstSupportedAddr(filter
func(IP
) IP
, addrs
[]string) IP
{
36 for _
, s
:= range addrs
{
37 if addr
:= filter(ParseIP(s
)); addr
!= nil {
44 func anyaddr(x IP
) IP
{
45 if x4
:= x
.To4(); x4
!= nil {
54 func ipv4only(x IP
) IP
{ return x
.To4() }
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
{
65 type InvalidAddrError
string
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 }
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 host
, port
, _
, err
= splitHostPort(hostport
)
79 func splitHostPort(hostport
string) (host
, port
, zone
string, err error
) {
80 // The port starts after the last colon.
81 i
:= last(hostport
, ':')
83 err
= &AddrError
{"missing port in address", hostport
}
86 host
, port
= hostport
[:i
], hostport
[i
+1:]
87 // Can put brackets around host ...
88 if len(host
) > 0 && host
[0] == '[' && host
[len(host
)-1] == ']' {
89 host
= host
[1 : len(host
)-1]
91 // ... but if there are no brackets, no colons.
92 if byteIndex(host
, ':') >= 0 {
93 err
= &AddrError
{"too many colons in address", hostport
}
100 // JoinHostPort combines host and port into a network address
101 // of the form "host:port" or, if host contains a colon, "[host]:port".
102 func JoinHostPort(host
, port
string) string {
103 // If host has colons, have to bracket it.
104 if byteIndex(host
, ':') >= 0 {
105 return "[" + host
+ "]:" + port
107 return host
+ ":" + port
110 func resolveInternetAddr(net
, addr
string, deadline time
.Time
) (Addr
, error
) {
113 host
, port
, zone
string
117 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
119 if host
, port
, zone
, err
= splitHostPort(addr
); err
!= nil {
122 if portnum
, err
= parsePort(net
, port
); err
!= nil {
126 case "ip", "ip4", "ip6":
131 return nil, UnknownNetworkError(net
)
133 inetaddr
:= func(net
string, ip IP
, port
int, zone
string) Addr
{
135 case "tcp", "tcp4", "tcp6":
136 return &TCPAddr
{IP
: ip
, Port
: port
, Zone
: zone
}
137 case "udp", "udp4", "udp6":
138 return &UDPAddr
{IP
: ip
, Port
: port
, Zone
: zone
}
139 case "ip", "ip4", "ip6":
140 return &IPAddr
{IP
: ip
, Zone
: zone
}
145 return inetaddr(net
, nil, portnum
, zone
), nil
147 // Try as an IP address.
148 if ip
:= ParseIP(host
); ip
!= nil {
149 return inetaddr(net
, ip
, portnum
, zone
), nil
151 var filter
func(IP
) IP
152 if net
!= "" && net
[len(net
)-1] == '4' {
155 if net
!= "" && net
[len(net
)-1] == '6' {
158 // Try as a DNS name.
159 addrs
, err
:= lookupHostDeadline(host
, deadline
)
163 ip
:= firstFavoriteAddr(filter
, addrs
)
166 return nil, &AddrError
{"LookupHost returned no suitable address", addrs
[0]}
168 return inetaddr(net
, ip
, portnum
, zone
), nil
171 func zoneToString(zone
int) string {
175 if ifi
, err
:= InterfaceByIndex(zone
); err
== nil {
178 return itod(uint(zone
))
181 func zoneToInt(zone
string) int {
185 if ifi
, err
:= InterfaceByName(zone
); err
== nil {
188 n
, _
, _
:= dtoi(zone
, 0)