Source file src/pkg/net/ipsock_posix.go
1
2
3
4
5
6
7
8
9 package net
10
11 import (
12 "syscall"
13 "time"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
30 var probes = []struct {
31 la TCPAddr
32 ok bool
33 }{
34
35 {TCPAddr{IP: ParseIP("::1")}, false},
36
37 {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
38 }
39
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
44 }
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
50 }
51 err = syscall.Bind(s, sa)
52 if err != nil {
53 continue
54 }
55 probes[i].ok = true
56 }
57
58 return probes[0].ok, probes[1].ok
59 }
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
103 }
104
105 if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
106 if supportsIPv4map {
107 return syscall.AF_INET6, false
108 }
109 if laddr == nil {
110 return syscall.AF_INET, false
111 }
112 return laddr.family(), false
113 }
114
115 if (laddr == nil || laddr.family() == syscall.AF_INET) &&
116 (raddr == nil || raddr.family() == syscall.AF_INET) {
117 return syscall.AF_INET, false
118 }
119 return syscall.AF_INET6, false
120 }
121
122
123
124
125
126 type sockaddr interface {
127 Addr
128 family() int
129 isWildcard() bool
130 sockaddr(family int) (syscall.Sockaddr, error)
131 }
132
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
139 }
140 }
141 if raddr != nil {
142 if ra, err = raddr.sockaddr(family); err != nil {
143 goto Error
144 }
145 }
146 fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, deadline, toAddr)
147 if err != nil {
148 goto Error
149 }
150 return fd, nil
151
152 Error:
153 addr := raddr
154 if mode == "listen" {
155 addr = laddr
156 }
157 return nil, &OpError{mode, net, addr, err}
158 }
159
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
165 }
166 if ip = ip.To4(); ip == nil {
167 return nil, InvalidAddrError("non-IPv4 address")
168 }
169 sa := new(syscall.SockaddrInet4)
170 for i := 0; i < IPv4len; i++ {
171 sa.Addr[i] = ip[i]
172 }
173 sa.Port = port
174 return sa, nil
175 case syscall.AF_INET6:
176 if len(ip) == 0 {
177 ip = IPv6zero
178 }
179
180
181
182 if ip.Equal(IPv4zero) {
183 ip = IPv6zero
184 }
185 if ip = ip.To16(); ip == nil {
186 return nil, InvalidAddrError("non-IPv6 address")
187 }
188 sa := new(syscall.SockaddrInet6)
189 for i := 0; i < IPv6len; i++ {
190 sa.Addr[i] = ip[i]
191 }
192 sa.Port = port
193 sa.ZoneId = uint32(zoneToInt(zone))
194 return sa, nil
195 }
196 return nil, InvalidAddrError("unexpected socket family")
197 }
View as plain text