2013-02-11 Sebastian Huber <sebastian.huber@embedded-brains.de>
[official-gcc.git] / libgo / go / net / ipsock.go
blob5636c85b4ffb91ede85f514e76bee76ecb057a47
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
7 package net
9 import "time"
11 var supportsIPv6, supportsIPv4map bool
13 func init() {
14 sysInit()
15 supportsIPv6, supportsIPv4map = probeIPv6Stack()
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)
29 } else {
30 addr = firstSupportedAddr(filter, addrs)
32 return
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
41 return nil
44 func anyaddr(x IP) IP {
45 if x4 := x.To4(); x4 != nil {
46 return x4
48 if supportsIPv6 {
49 return x
51 return 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 {
60 return x
62 return nil
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)
76 return
79 func splitHostPort(hostport string) (host, port, zone string, err error) {
80 // The port starts after the last colon.
81 i := last(hostport, ':')
82 if i < 0 {
83 err = &AddrError{"missing port in address", hostport}
84 return
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]
90 } else {
91 // ... but if there are no brackets, no colons.
92 if byteIndex(host, ':') >= 0 {
93 err = &AddrError{"too many colons in address", hostport}
94 return
97 return
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) {
111 var (
112 err error
113 host, port, zone string
114 portnum int
116 switch net {
117 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
118 if addr != "" {
119 if host, port, zone, err = splitHostPort(addr); err != nil {
120 return nil, err
122 if portnum, err = parsePort(net, port); err != nil {
123 return nil, err
126 case "ip", "ip4", "ip6":
127 if addr != "" {
128 host = addr
130 default:
131 return nil, UnknownNetworkError(net)
133 inetaddr := func(net string, ip IP, port int, zone string) Addr {
134 switch net {
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}
142 return nil
144 if host == "" {
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' {
153 filter = ipv4only
155 if net != "" && net[len(net)-1] == '6' {
156 filter = ipv6only
158 // Try as a DNS name.
159 addrs, err := lookupHostDeadline(host, deadline)
160 if err != nil {
161 return nil, err
163 ip := firstFavoriteAddr(filter, addrs)
164 if ip == nil {
165 // should not happen
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 {
172 if zone == 0 {
173 return ""
175 if ifi, err := InterfaceByIndex(zone); err == nil {
176 return ifi.Name
178 return itod(uint(zone))
181 func zoneToInt(zone string) int {
182 if zone == "" {
183 return 0
185 if ifi, err := InterfaceByName(zone); err == nil {
186 return ifi.Index
188 n, _, _ := dtoi(zone, 0)
189 return n