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.
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" {
25 fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
32 var preferIPv4 = !kernelSupportsIPv6()
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 }
39 // Internet sockets (TCP, UDP)
41 // A sockaddr represents a TCP or UDP network address that can
42 // be converted into a syscall.Sockaddr.
43 type sockaddr interface {
45 sockaddr(family int) (syscall.Sockaddr, os.Error)
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.
53 family := syscall.AF_INET6
54 switch net[len(net)-1] {
56 family = syscall.AF_INET
61 // If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
63 (laddr == nil || laddr.family() == syscall.AF_INET) &&
64 (raddr == nil || raddr.family() == syscall.AF_INET) {
65 family = syscall.AF_INET
69 var la, ra syscall.Sockaddr
71 if la, oserr = laddr.sockaddr(family); oserr != nil {
76 if ra, oserr = raddr.sockaddr(family); oserr != nil {
80 fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
91 return nil, &OpError{mode, net, addr, oserr}
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
100 sa, _ = syscall.Getpeername(fd)
102 sa, _ = syscall.Getsockname(fd)
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
113 type InvalidAddrError string
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 }
120 func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
122 case syscall.AF_INET:
126 if ip = ip.To4(); ip == nil {
127 return nil, InvalidAddrError("non-IPv4 address")
129 s := new(syscall.SockaddrInet4)
130 for i := 0; i < IPv4len; i++ {
135 case syscall.AF_INET6:
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 {
145 if ip = ip.To16(); ip == nil {
146 return nil, InvalidAddrError("non-IPv6 address")
148 s := new(syscall.SockaddrInet6)
149 for i := 0; i < IPv6len; i++ {
155 return nil, InvalidAddrError("unexpected socket family")
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, ':')
164 err = &AddrError{"missing port in address", hostport}
168 host, port = hostport[0:i], hostport[i+1:]
170 // Can put brackets around host ...
171 if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
172 host = host[1 : len(host)-1]
174 // ... but if there are no brackets, no colons.
175 if byteIndex(host, ':') >= 0 {
176 err = &AddrError{"too many colons in address", hostport}
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
190 return host + ":" + port
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)
202 // Try as an IP address.
205 // Not an IP address. Try as a DNS name.
206 _, addrs, err1 := LookupHost(host)
211 addr = ParseIP(addrs[0])
214 err = &AddrError{"LookupHost returned invalid address", addrs[0]}
220 p, i, ok := dtoi(port, 0)
221 if !ok || i != len(port) {
222 p, err = LookupPort(net, port)
227 if p < 0 || p > 0xFFFF {
228 err = &AddrError{"invalid port", port}