2017-07-18 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / go / net / sock_posix.go
blob6bbfd1208ee807ae42a539880d4f67e10256e952
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 aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
7 package net
9 import (
10 "context"
11 "os"
12 "syscall"
15 // A sockaddr represents a TCP, UDP, IP or Unix network endpoint
16 // address that can be converted into a syscall.Sockaddr.
17 type sockaddr interface {
18 Addr
20 // family returns the platform-dependent address family
21 // identifier.
22 family() int
24 // isWildcard reports whether the address is a wildcard
25 // address.
26 isWildcard() bool
28 // sockaddr returns the address converted into a syscall
29 // sockaddr type that implements syscall.Sockaddr
30 // interface. It returns a nil interface when the address is
31 // nil.
32 sockaddr(family int) (syscall.Sockaddr, error)
34 // toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
35 toLocal(net string) sockaddr
38 // socket returns a network file descriptor that is ready for
39 // asynchronous I/O using the network poller.
40 func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr) (fd *netFD, err error) {
41 s, err := sysSocket(family, sotype, proto)
42 if err != nil {
43 return nil, err
45 if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
46 closeFunc(s)
47 return nil, err
49 if fd, err = newFD(s, family, sotype, net); err != nil {
50 closeFunc(s)
51 return nil, err
54 // This function makes a network file descriptor for the
55 // following applications:
57 // - An endpoint holder that opens a passive stream
58 // connection, known as a stream listener
60 // - An endpoint holder that opens a destination-unspecific
61 // datagram connection, known as a datagram listener
63 // - An endpoint holder that opens an active stream or a
64 // destination-specific datagram connection, known as a
65 // dialer
67 // - An endpoint holder that opens the other connection, such
68 // as talking to the protocol stack inside the kernel
70 // For stream and datagram listeners, they will only require
71 // named sockets, so we can assume that it's just a request
72 // from stream or datagram listeners when laddr is not nil but
73 // raddr is nil. Otherwise we assume it's just for dialers or
74 // the other connection holders.
76 if laddr != nil && raddr == nil {
77 switch sotype {
78 case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
79 if err := fd.listenStream(laddr, listenerBacklog); err != nil {
80 fd.Close()
81 return nil, err
83 return fd, nil
84 case syscall.SOCK_DGRAM:
85 if err := fd.listenDatagram(laddr); err != nil {
86 fd.Close()
87 return nil, err
89 return fd, nil
92 if err := fd.dial(ctx, laddr, raddr); err != nil {
93 fd.Close()
94 return nil, err
96 return fd, nil
99 func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
100 switch fd.family {
101 case syscall.AF_INET, syscall.AF_INET6:
102 switch fd.sotype {
103 case syscall.SOCK_STREAM:
104 return sockaddrToTCP
105 case syscall.SOCK_DGRAM:
106 return sockaddrToUDP
107 case syscall.SOCK_RAW:
108 return sockaddrToIP
110 case syscall.AF_UNIX:
111 switch fd.sotype {
112 case syscall.SOCK_STREAM:
113 return sockaddrToUnix
114 case syscall.SOCK_DGRAM:
115 return sockaddrToUnixgram
116 case syscall.SOCK_SEQPACKET:
117 return sockaddrToUnixpacket
120 return func(syscall.Sockaddr) Addr { return nil }
123 func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
124 var err error
125 var lsa syscall.Sockaddr
126 if laddr != nil {
127 if lsa, err = laddr.sockaddr(fd.family); err != nil {
128 return err
129 } else if lsa != nil {
130 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
131 return os.NewSyscallError("bind", err)
135 var rsa syscall.Sockaddr
136 if raddr != nil {
137 if rsa, err = raddr.sockaddr(fd.family); err != nil {
138 return err
140 if err := fd.connect(ctx, lsa, rsa); err != nil {
141 return err
143 fd.isConnected = true
144 } else {
145 if err := fd.init(); err != nil {
146 return err
149 lsa, _ = syscall.Getsockname(fd.sysfd)
150 if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
151 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
152 } else {
153 fd.setAddr(fd.addrFunc()(lsa), raddr)
155 return nil
158 func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
159 if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
160 return err
162 if lsa, err := laddr.sockaddr(fd.family); err != nil {
163 return err
164 } else if lsa != nil {
165 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
166 return os.NewSyscallError("bind", err)
169 if err := listenFunc(fd.sysfd, backlog); err != nil {
170 return os.NewSyscallError("listen", err)
172 if err := fd.init(); err != nil {
173 return err
175 lsa, _ := syscall.Getsockname(fd.sysfd)
176 fd.setAddr(fd.addrFunc()(lsa), nil)
177 return nil
180 func (fd *netFD) listenDatagram(laddr sockaddr) error {
181 switch addr := laddr.(type) {
182 case *UDPAddr:
183 // We provide a socket that listens to a wildcard
184 // address with reusable UDP port when the given laddr
185 // is an appropriate UDP multicast address prefix.
186 // This makes it possible for a single UDP listener to
187 // join multiple different group addresses, for
188 // multiple UDP listeners that listen on the same UDP
189 // port to join the same group address.
190 if addr.IP != nil && addr.IP.IsMulticast() {
191 if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
192 return err
194 addr := *addr
195 switch fd.family {
196 case syscall.AF_INET:
197 addr.IP = IPv4zero
198 case syscall.AF_INET6:
199 addr.IP = IPv6unspecified
201 laddr = &addr
204 if lsa, err := laddr.sockaddr(fd.family); err != nil {
205 return err
206 } else if lsa != nil {
207 if err := syscall.Bind(fd.sysfd, lsa); err != nil {
208 return os.NewSyscallError("bind", err)
211 if err := fd.init(); err != nil {
212 return err
214 lsa, _ := syscall.Getsockname(fd.sysfd)
215 fd.setAddr(fd.addrFunc()(lsa), nil)
216 return nil