4ba6a55b96f70cae0d09065620deaac9f027eeab
[platform/upstream/gcc.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 import (
10         "os"
11         "syscall"
12 )
13
14 // Should we try to use the IPv4 socket interface if we're
15 // only dealing with IPv4 sockets?  As long as the host system
16 // understands IPv6, it's okay to pass IPv4 addresses to the IPv6
17 // interface.  That simplifies our code and is most general.
18 // Unfortunately, we need to run on kernels built without IPv6 support too.
19 // So probe the kernel to figure it out.
20 func kernelSupportsIPv6() bool {
21         // FreeBSD does not support this sort of interface.
22         if syscall.OS == "freebsd" {
23                 return false
24         }
25         fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
26         if fd >= 0 {
27                 closesocket(fd)
28         }
29         return e == 0
30 }
31
32 var preferIPv4 = !kernelSupportsIPv6()
33
34 // TODO(rsc): if syscall.OS == "linux", we're supposd to read
35 // /proc/sys/net/core/somaxconn,
36 // to take advantage of kernels that have raised the limit.
37 func listenBacklog() int { return syscall.SOMAXCONN }
38
39 // Internet sockets (TCP, UDP)
40
41 // A sockaddr represents a TCP or UDP network address that can
42 // be converted into a syscall.Sockaddr.
43 type sockaddr interface {
44         Addr
45         sockaddr(family int) (syscall.Sockaddr, os.Error)
46         family() int
47 }
48
49 func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
50         // Figure out IP version.
51         // If network has a suffix like "tcp4", obey it.
52         var oserr os.Error
53         family := syscall.AF_INET6
54         switch net[len(net)-1] {
55         case '4':
56                 family = syscall.AF_INET
57         case '6':
58                 // nothing to do
59         default:
60                 // Otherwise, guess.
61                 // If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
62                 if preferIPv4 &&
63                         (laddr == nil || laddr.family() == syscall.AF_INET) &&
64                         (raddr == nil || raddr.family() == syscall.AF_INET) {
65                         family = syscall.AF_INET
66                 }
67         }
68
69         var la, ra syscall.Sockaddr
70         if laddr != nil {
71                 if la, oserr = laddr.sockaddr(family); oserr != nil {
72                         goto Error
73                 }
74         }
75         if raddr != nil {
76                 if ra, oserr = raddr.sockaddr(family); oserr != nil {
77                         goto Error
78                 }
79         }
80         fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
81         if oserr != nil {
82                 goto Error
83         }
84         return fd, nil
85
86 Error:
87         addr := raddr
88         if mode == "listen" {
89                 addr = laddr
90         }
91         return nil, &OpError{mode, net, addr, oserr}
92 }
93
94 func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
95         // No attempt at error reporting because
96         // there are no possible errors, and the
97         // caller won't report them anyway.
98         var sa syscall.Sockaddr
99         if remote {
100                 sa, _ = syscall.Getpeername(fd)
101         } else {
102                 sa, _ = syscall.Getsockname(fd)
103         }
104         switch sa := sa.(type) {
105         case *syscall.SockaddrInet4:
106                 return sa.Addr[0:], sa.Port, true
107         case *syscall.SockaddrInet6:
108                 return sa.Addr[0:], sa.Port, true
109         }
110         return
111 }
112
113 type InvalidAddrError string
114
115 func (e InvalidAddrError) String() string  { return string(e) }
116 func (e InvalidAddrError) Timeout() bool   { return false }
117 func (e InvalidAddrError) Temporary() bool { return false }
118
119
120 func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
121         switch family {
122         case syscall.AF_INET:
123                 if len(ip) == 0 {
124                         ip = IPv4zero
125                 }
126                 if ip = ip.To4(); ip == nil {
127                         return nil, InvalidAddrError("non-IPv4 address")
128                 }
129                 s := new(syscall.SockaddrInet4)
130                 for i := 0; i < IPv4len; i++ {
131                         s.Addr[i] = ip[i]
132                 }
133                 s.Port = port
134                 return s, nil
135         case syscall.AF_INET6:
136                 if len(ip) == 0 {
137                         ip = IPzero
138                 }
139                 // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
140                 // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
141                 // which it refuses to do.  Rewrite to the IPv6 all zeros.
142                 if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 {
143                         ip = IPzero
144                 }
145                 if ip = ip.To16(); ip == nil {
146                         return nil, InvalidAddrError("non-IPv6 address")
147                 }
148                 s := new(syscall.SockaddrInet6)
149                 for i := 0; i < IPv6len; i++ {
150                         s.Addr[i] = ip[i]
151                 }
152                 s.Port = port
153                 return s, nil
154         }
155         return nil, InvalidAddrError("unexpected socket family")
156 }
157
158 // Split "host:port" into "host" and "port".
159 // Host cannot contain colons unless it is bracketed.
160 func splitHostPort(hostport string) (host, port string, err os.Error) {
161         // The port starts after the last colon.
162         i := last(hostport, ':')
163         if i < 0 {
164                 err = &AddrError{"missing port in address", hostport}
165                 return
166         }
167
168         host, port = hostport[0:i], hostport[i+1:]
169
170         // Can put brackets around host ...
171         if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
172                 host = host[1 : len(host)-1]
173         } else {
174                 // ... but if there are no brackets, no colons.
175                 if byteIndex(host, ':') >= 0 {
176                         err = &AddrError{"too many colons in address", hostport}
177                         return
178                 }
179         }
180         return
181 }
182
183 // Join "host" and "port" into "host:port".
184 // If host contains colons, will join into "[host]:port".
185 func joinHostPort(host, port string) string {
186         // If host has colons, have to bracket it.
187         if byteIndex(host, ':') >= 0 {
188                 return "[" + host + "]:" + port
189         }
190         return host + ":" + port
191 }
192
193 // Convert "host:port" into IP address and port.
194 func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
195         host, port, err := splitHostPort(hostport)
196         if err != nil {
197                 goto Error
198         }
199
200         var addr IP
201         if host != "" {
202                 // Try as an IP address.
203                 addr = ParseIP(host)
204                 if addr == nil {
205                         // Not an IP address.  Try as a DNS name.
206                         _, addrs, err1 := LookupHost(host)
207                         if err1 != nil {
208                                 err = err1
209                                 goto Error
210                         }
211                         addr = ParseIP(addrs[0])
212                         if addr == nil {
213                                 // should not happen
214                                 err = &AddrError{"LookupHost returned invalid address", addrs[0]}
215                                 goto Error
216                         }
217                 }
218         }
219
220         p, i, ok := dtoi(port, 0)
221         if !ok || i != len(port) {
222                 p, err = LookupPort(net, port)
223                 if err != nil {
224                         goto Error
225                 }
226         }
227         if p < 0 || p > 0xFFFF {
228                 err = &AddrError{"invalid port", port}
229                 goto Error
230         }
231
232         return addr, p, nil
233
234 Error:
235         return nil, 0, err
236 }