Imported Upstream version 4.7.2
[platform/upstream/gcc48.git] / libgo / go / net / ipsock.go
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.
4
5 // IP sockets
6
7 package net
8
9 var supportsIPv6, supportsIPv4map = probeIPv6Stack()
10
11 func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
12         if filter == nil {
13                 // We'll take any IP address, but since the dialing code
14                 // does not yet try multiple addresses, prefer to use
15                 // an IPv4 address if possible.  This is especially relevant
16                 // if localhost resolves to [ipv6-localhost, ipv4-localhost].
17                 // Too much code assumes localhost == ipv4-localhost.
18                 addr = firstSupportedAddr(ipv4only, addrs)
19                 if addr == nil {
20                         addr = firstSupportedAddr(anyaddr, addrs)
21                 }
22         } else {
23                 addr = firstSupportedAddr(filter, addrs)
24         }
25         return
26 }
27
28 func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
29         for _, s := range addrs {
30                 if addr := filter(ParseIP(s)); addr != nil {
31                         return addr
32                 }
33         }
34         return nil
35 }
36
37 func anyaddr(x IP) IP {
38         if x4 := x.To4(); x4 != nil {
39                 return x4
40         }
41         if supportsIPv6 {
42                 return x
43         }
44         return nil
45 }
46
47 func ipv4only(x IP) IP { return x.To4() }
48
49 func ipv6only(x IP) IP {
50         // Only return addresses that we can use
51         // with the kernel's IPv6 addressing modes.
52         if len(x) == IPv6len && x.To4() == nil && supportsIPv6 {
53                 return x
54         }
55         return nil
56 }
57
58 type InvalidAddrError string
59
60 func (e InvalidAddrError) Error() string   { return string(e) }
61 func (e InvalidAddrError) Timeout() bool   { return false }
62 func (e InvalidAddrError) Temporary() bool { return false }
63
64 // SplitHostPort splits a network address of the form
65 // "host:port" or "[host]:port" into host and port.
66 // The latter form must be used when host contains a colon.
67 func SplitHostPort(hostport string) (host, port string, err error) {
68         // The port starts after the last colon.
69         i := last(hostport, ':')
70         if i < 0 {
71                 err = &AddrError{"missing port in address", hostport}
72                 return
73         }
74
75         host, port = hostport[0:i], hostport[i+1:]
76
77         // Can put brackets around host ...
78         if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
79                 host = host[1 : len(host)-1]
80         } else {
81                 // ... but if there are no brackets, no colons.
82                 if byteIndex(host, ':') >= 0 {
83                         err = &AddrError{"too many colons in address", hostport}
84                         return
85                 }
86         }
87         return
88 }
89
90 // JoinHostPort combines host and port into a network address
91 // of the form "host:port" or, if host contains a colon, "[host]:port".
92 func JoinHostPort(host, port string) string {
93         // If host has colons, have to bracket it.
94         if byteIndex(host, ':') >= 0 {
95                 return "[" + host + "]:" + port
96         }
97         return host + ":" + port
98 }
99
100 // Convert "host:port" into IP address and port.
101 func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
102         host, port, err := SplitHostPort(hostport)
103         if err != nil {
104                 return nil, 0, err
105         }
106
107         var addr IP
108         if host != "" {
109                 // Try as an IP address.
110                 addr = ParseIP(host)
111                 if addr == nil {
112                         var filter func(IP) IP
113                         if net != "" && net[len(net)-1] == '4' {
114                                 filter = ipv4only
115                         }
116                         if net != "" && net[len(net)-1] == '6' {
117                                 filter = ipv6only
118                         }
119                         // Not an IP address.  Try as a DNS name.
120                         addrs, err := LookupHost(host)
121                         if err != nil {
122                                 return nil, 0, err
123                         }
124                         addr = firstFavoriteAddr(filter, addrs)
125                         if addr == nil {
126                                 // should not happen
127                                 return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
128                         }
129                 }
130         }
131
132         p, i, ok := dtoi(port, 0)
133         if !ok || i != len(port) {
134                 p, err = LookupPort(net, port)
135                 if err != nil {
136                         return nil, 0, err
137                 }
138         }
139         if p < 0 || p > 0xFFFF {
140                 return nil, 0, &AddrError{"invalid port", port}
141         }
142
143         return addr, p, nil
144
145 }