* gcc.dg/guality/guality.exp: Skip on AIX.
[official-gcc.git] / libgo / go / net / ipsock_posix.go
blob4c37616ecf861d8f0fd11b008a8c4556d11df570
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 // +build darwin freebsd linux netbsd openbsd windows
7 // Internet protocol family sockets for POSIX
9 package net
11 import (
12 "syscall"
13 "time"
16 // Should we try to use the IPv4 socket interface if we're
17 // only dealing with IPv4 sockets? As long as the host system
18 // understands IPv6, it's okay to pass IPv4 addresses to the IPv6
19 // interface. That simplifies our code and is most general.
20 // Unfortunately, we need to run on kernels built without IPv6
21 // support too. So probe the kernel to figure it out.
23 // probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
24 // mapping capability which is controlled by IPV6_V6ONLY socket
25 // option and/or kernel state "net.inet6.ip6.v6only".
26 // It returns two boolean values. If the first boolean value is
27 // true, kernel supports basic IPv6 functionality. If the second
28 // boolean value is true, kernel supports IPv6 IPv4-mapping.
29 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
30 var probes = []struct {
31 la TCPAddr
32 ok bool
34 // IPv6 communication capability
35 {TCPAddr{IP: ParseIP("::1")}, false},
36 // IPv6 IPv4-mapped address communication capability
37 {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
40 for i := range probes {
41 s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
42 if err != nil {
43 continue
45 defer closesocket(s)
46 syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
47 sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
48 if err != nil {
49 continue
51 err = syscall.Bind(s, sa)
52 if err != nil {
53 continue
55 probes[i].ok = true
58 return probes[0].ok, probes[1].ok
61 // favoriteAddrFamily returns the appropriate address family to
62 // the given net, laddr, raddr and mode. At first it figures
63 // address family out from the net. If mode indicates "listen"
64 // and laddr is a wildcard, it assumes that the user wants to
65 // make a passive connection with a wildcard address family, both
66 // AF_INET and AF_INET6, and a wildcard address like following:
68 // 1. A wild-wild listen, "tcp" + ""
69 // If the platform supports both IPv6 and IPv6 IPv4-mapping
70 // capabilities, we assume that the user want to listen on
71 // both IPv4 and IPv6 wildcard address over an AF_INET6
72 // socket with IPV6_V6ONLY=0. Otherwise we prefer an IPv4
73 // wildcard address listen over an AF_INET socket.
75 // 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
76 // Same as 1.
78 // 3. A wild-ipv6wild listen, "tcp" + "[::]"
79 // Almost same as 1 but we prefer an IPv6 wildcard address
80 // listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
81 // the platform supports IPv6 capability but not IPv6 IPv4-
82 // mapping capability.
84 // 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
85 // We use an IPv4 (AF_INET) wildcard address listen.
87 // 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
88 // We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
89 // listen.
91 // Otherwise guess: if the addresses are IPv4 then returns AF_INET,
92 // or else returns AF_INET6. It also returns a boolean value what
93 // designates IPV6_V6ONLY option.
95 // Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
96 // nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
97 func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
98 switch net[len(net)-1] {
99 case '4':
100 return syscall.AF_INET, false
101 case '6':
102 return syscall.AF_INET6, true
105 if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
106 if supportsIPv4map {
107 return syscall.AF_INET6, false
109 if laddr == nil {
110 return syscall.AF_INET, false
112 return laddr.family(), false
115 if (laddr == nil || laddr.family() == syscall.AF_INET) &&
116 (raddr == nil || raddr.family() == syscall.AF_INET) {
117 return syscall.AF_INET, false
119 return syscall.AF_INET6, false
122 // Internet sockets (TCP, UDP, IP)
124 // A sockaddr represents a TCP, UDP or IP network address that can
125 // be converted into a syscall.Sockaddr.
126 type sockaddr interface {
127 Addr
128 family() int
129 isWildcard() bool
130 sockaddr(family int) (syscall.Sockaddr, error)
133 func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
134 var la, ra syscall.Sockaddr
135 family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
136 if laddr != nil {
137 if la, err = laddr.sockaddr(family); err != nil {
138 goto Error
141 if raddr != nil {
142 if ra, err = raddr.sockaddr(family); err != nil {
143 goto Error
146 fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
147 if err != nil {
148 goto Error
150 return fd, nil
152 Error:
153 addr := raddr
154 if mode == "listen" {
155 addr = laddr
157 return nil, &OpError{mode, net, addr, err}
160 func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
161 switch family {
162 case syscall.AF_INET:
163 if len(ip) == 0 {
164 ip = IPv4zero
166 if ip = ip.To4(); ip == nil {
167 return nil, InvalidAddrError("non-IPv4 address")
169 sa := new(syscall.SockaddrInet4)
170 for i := 0; i < IPv4len; i++ {
171 sa.Addr[i] = ip[i]
173 sa.Port = port
174 return sa, nil
175 case syscall.AF_INET6:
176 if len(ip) == 0 {
177 ip = IPv6zero
179 // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
180 // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
181 // which it refuses to do. Rewrite to the IPv6 unspecified address.
182 if ip.Equal(IPv4zero) {
183 ip = IPv6zero
185 if ip = ip.To16(); ip == nil {
186 return nil, InvalidAddrError("non-IPv6 address")
188 sa := new(syscall.SockaddrInet6)
189 for i := 0; i < IPv6len; i++ {
190 sa.Addr[i] = ip[i]
192 sa.Port = port
193 sa.ZoneId = uint32(zoneToInt(zone))
194 return sa, nil
196 return nil, InvalidAddrError("unexpected socket family")