net: check Getsockname error return
[official-gcc.git] / libgo / go / net / sock_posix.go
blob4733c422f1644909cc291286d7cb2e0d79f45fb2
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 "internal/poll"
12 "os"
13 "syscall"
16 // A sockaddr represents a TCP, UDP, IP or Unix network endpoint
17 // address that can be converted into a syscall.Sockaddr.
18 type sockaddr interface {
19 Addr
21 // family returns the platform-dependent address family
22 // identifier.
23 family() int
25 // isWildcard reports whether the address is a wildcard
26 // address.
27 isWildcard() bool
29 // sockaddr returns the address converted into a syscall
30 // sockaddr type that implements syscall.Sockaddr
31 // interface. It returns a nil interface when the address is
32 // nil.
33 sockaddr(family int) (syscall.Sockaddr, error)
35 // toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
36 toLocal(net string) sockaddr
39 // socket returns a network file descriptor that is ready for
40 // asynchronous I/O using the network poller.
41 func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr) (fd *netFD, err error) {
42 s, err := sysSocket(family, sotype, proto)
43 if err != nil {
44 return nil, err
46 if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
47 poll.CloseFunc(s)
48 return nil, err
50 if fd, err = newFD(s, family, sotype, net); err != nil {
51 poll.CloseFunc(s)
52 return nil, err
55 // This function makes a network file descriptor for the
56 // following applications:
58 // - An endpoint holder that opens a passive stream
59 // connection, known as a stream listener
61 // - An endpoint holder that opens a destination-unspecific
62 // datagram connection, known as a datagram listener
64 // - An endpoint holder that opens an active stream or a
65 // destination-specific datagram connection, known as a
66 // dialer
68 // - An endpoint holder that opens the other connection, such
69 // as talking to the protocol stack inside the kernel
71 // For stream and datagram listeners, they will only require
72 // named sockets, so we can assume that it's just a request
73 // from stream or datagram listeners when laddr is not nil but
74 // raddr is nil. Otherwise we assume it's just for dialers or
75 // the other connection holders.
77 if laddr != nil && raddr == nil {
78 switch sotype {
79 case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
80 if err := fd.listenStream(laddr, listenerBacklog); err != nil {
81 fd.Close()
82 return nil, err
84 return fd, nil
85 case syscall.SOCK_DGRAM:
86 if err := fd.listenDatagram(laddr); err != nil {
87 fd.Close()
88 return nil, err
90 return fd, nil
93 if err := fd.dial(ctx, laddr, raddr); err != nil {
94 fd.Close()
95 return nil, err
97 return fd, nil
100 func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
101 switch fd.family {
102 case syscall.AF_INET, syscall.AF_INET6:
103 switch fd.sotype {
104 case syscall.SOCK_STREAM:
105 return sockaddrToTCP
106 case syscall.SOCK_DGRAM:
107 return sockaddrToUDP
108 case syscall.SOCK_RAW:
109 return sockaddrToIP
111 case syscall.AF_UNIX:
112 switch fd.sotype {
113 case syscall.SOCK_STREAM:
114 return sockaddrToUnix
115 case syscall.SOCK_DGRAM:
116 return sockaddrToUnixgram
117 case syscall.SOCK_SEQPACKET:
118 return sockaddrToUnixpacket
121 return func(syscall.Sockaddr) Addr { return nil }
124 func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
125 var err error
126 var lsa syscall.Sockaddr
127 if laddr != nil {
128 if lsa, err = laddr.sockaddr(fd.family); err != nil {
129 return err
130 } else if lsa != nil {
131 if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
132 return os.NewSyscallError("bind", err)
136 var rsa syscall.Sockaddr // remote address from the user
137 var crsa syscall.Sockaddr // remote address we actually connected to
138 if raddr != nil {
139 if rsa, err = raddr.sockaddr(fd.family); err != nil {
140 return err
142 if crsa, err = fd.connect(ctx, lsa, rsa); err != nil {
143 return err
145 fd.isConnected = true
146 } else {
147 if err := fd.init(); err != nil {
148 return err
151 // Record the local and remote addresses from the actual socket.
152 // Get the local address by calling Getsockname.
153 // For the remote address, use
154 // 1) the one returned by the connect method, if any; or
155 // 2) the one from Getpeername, if it succeeds; or
156 // 3) the one passed to us as the raddr parameter.
157 lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
158 if crsa != nil {
159 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(crsa))
160 } else if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
161 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
162 } else {
163 fd.setAddr(fd.addrFunc()(lsa), raddr)
165 return nil
168 func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
169 if err := setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
170 return err
172 if lsa, err := laddr.sockaddr(fd.family); err != nil {
173 return err
174 } else if lsa != nil {
175 if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
176 return os.NewSyscallError("bind", err)
179 if err := listenFunc(fd.pfd.Sysfd, backlog); err != nil {
180 return os.NewSyscallError("listen", err)
182 if err := fd.init(); err != nil {
183 return err
185 lsa, err := syscall.Getsockname(fd.pfd.Sysfd)
186 if err != nil {
187 return os.NewSyscallError("getsockname", err)
189 fd.setAddr(fd.addrFunc()(lsa), nil)
190 return nil
193 func (fd *netFD) listenDatagram(laddr sockaddr) error {
194 switch addr := laddr.(type) {
195 case *UDPAddr:
196 // We provide a socket that listens to a wildcard
197 // address with reusable UDP port when the given laddr
198 // is an appropriate UDP multicast address prefix.
199 // This makes it possible for a single UDP listener to
200 // join multiple different group addresses, for
201 // multiple UDP listeners that listen on the same UDP
202 // port to join the same group address.
203 if addr.IP != nil && addr.IP.IsMulticast() {
204 if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
205 return err
207 addr := *addr
208 switch fd.family {
209 case syscall.AF_INET:
210 addr.IP = IPv4zero
211 case syscall.AF_INET6:
212 addr.IP = IPv6unspecified
214 laddr = &addr
217 if lsa, err := laddr.sockaddr(fd.family); err != nil {
218 return err
219 } else if lsa != nil {
220 if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
221 return os.NewSyscallError("bind", err)
224 if err := fd.init(); err != nil {
225 return err
227 lsa, err := syscall.Getsockname(fd.pfd.Sysfd)
228 if err != nil {
229 return os.NewSyscallError("getsockname", err)
231 fd.setAddr(fd.addrFunc()(lsa), nil)
232 return nil