summaryrefslogtreecommitdiff
path: root/libgo/go/net/ipsock.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/ipsock.go')
-rw-r--r--libgo/go/net/ipsock.go114
1 files changed, 86 insertions, 28 deletions
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index 5636c85b4ff..d930595879c 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -68,40 +68,94 @@ func (e InvalidAddrError) Error() string { return string(e) }
func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
-// SplitHostPort splits a network address of the form
-// "host:port" or "[host]:port" into host and port.
-// The latter form must be used when host contains a colon.
+// SplitHostPort splits a network address of the form "host:port",
+// "[host]:port" or "[ipv6-host%zone]:port" into host or
+// ipv6-host%zone and port. A literal address or host name for IPv6
+// must be enclosed in square brackets, as in "[::1]:80",
+// "[ipv6-host]:http" or "[ipv6-host%zone]:80".
func SplitHostPort(hostport string) (host, port string, err error) {
- host, port, _, err = splitHostPort(hostport)
- return
-}
+ j, k := 0, 0
-func splitHostPort(hostport string) (host, port, zone string, err error) {
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
- err = &AddrError{"missing port in address", hostport}
- return
+ goto missingPort
}
- host, port = hostport[:i], hostport[i+1:]
- // Can put brackets around host ...
- if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
- host = host[1 : len(host)-1]
+
+ if hostport[0] == '[' {
+ // Expect the first ']' just before the last ':'.
+ end := byteIndex(hostport, ']')
+ if end < 0 {
+ err = &AddrError{"missing ']' in address", hostport}
+ return
+ }
+ switch end + 1 {
+ case len(hostport):
+ // There can't be a ':' behind the ']' now.
+ goto missingPort
+ case i:
+ // The expected result.
+ default:
+ // Either ']' isn't followed by a colon, or it is
+ // followed by a colon that is not the last one.
+ if hostport[end+1] == ':' {
+ goto tooManyColons
+ }
+ goto missingPort
+ }
+ host = hostport[1:end]
+ j, k = 1, end+1 // there can't be a '[' resp. ']' before these positions
} else {
- // ... but if there are no brackets, no colons.
+ host = hostport[:i]
if byteIndex(host, ':') >= 0 {
- err = &AddrError{"too many colons in address", hostport}
- return
+ goto tooManyColons
}
+ if byteIndex(host, '%') >= 0 {
+ goto missingBrackets
+ }
+ }
+ if byteIndex(hostport[j:], '[') >= 0 {
+ err = &AddrError{"unexpected '[' in address", hostport}
+ return
+ }
+ if byteIndex(hostport[k:], ']') >= 0 {
+ err = &AddrError{"unexpected ']' in address", hostport}
+ return
+ }
+
+ port = hostport[i+1:]
+ return
+
+missingPort:
+ err = &AddrError{"missing port in address", hostport}
+ return
+
+tooManyColons:
+ err = &AddrError{"too many colons in address", hostport}
+ return
+
+missingBrackets:
+ err = &AddrError{"missing brackets in address", hostport}
+ return
+}
+
+func splitHostZone(s string) (host, zone string) {
+ // The IPv6 scoped addressing zone identifer starts after the
+ // last percent sign.
+ if i := last(s, '%'); i > 0 {
+ host, zone = s[:i], s[i+1:]
+ } else {
+ host = s
}
return
}
-// JoinHostPort combines host and port into a network address
-// of the form "host:port" or, if host contains a colon, "[host]:port".
+// JoinHostPort combines host and port into a network address of the
+// form "host:port" or, if host contains a colon or a percent sign,
+// "[host]:port".
func JoinHostPort(host, port string) string {
- // If host has colons, have to bracket it.
- if byteIndex(host, ':') >= 0 {
+ // If host has colons or a percent sign, have to bracket it.
+ if byteIndex(host, ':') >= 0 || byteIndex(host, '%') >= 0 {
return "[" + host + "]:" + port
}
return host + ":" + port
@@ -116,7 +170,7 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
switch net {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
if addr != "" {
- if host, port, zone, err = splitHostPort(addr); err != nil {
+ if host, port, err = SplitHostPort(addr); err != nil {
return nil, err
}
if portnum, err = parsePort(net, port); err != nil {
@@ -145,21 +199,25 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
return inetaddr(net, nil, portnum, zone), nil
}
// Try as an IP address.
- if ip := ParseIP(host); ip != nil {
+ if ip := parseIPv4(host); ip != nil {
+ return inetaddr(net, ip, portnum, zone), nil
+ }
+ if ip, zone := parseIPv6(host, true); ip != nil {
return inetaddr(net, ip, portnum, zone), nil
}
+ // Try as a domain name.
+ host, zone = splitHostZone(host)
+ addrs, err := lookupHostDeadline(host, deadline)
+ if err != nil {
+ return nil, err
+ }
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
- if net != "" && net[len(net)-1] == '6' {
+ if net != "" && net[len(net)-1] == '6' || zone != "" {
filter = ipv6only
}
- // Try as a DNS name.
- addrs, err := lookupHostDeadline(host, deadline)
- if err != nil {
- return nil, err
- }
ip := firstFavoriteAddr(filter, addrs)
if ip == nil {
// should not happen