]> Cypherpunks.ru repositories - gostls13.git/blob - src/net/sock_posix.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / net / sock_posix.go
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.
4
5 //go:build unix || windows
6
7 package net
8
9 import (
10         "context"
11         "internal/poll"
12         "os"
13         "syscall"
14 )
15
16 // socket returns a network file descriptor that is ready for
17 // asynchronous I/O using the network poller.
18 func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (fd *netFD, err error) {
19         s, err := sysSocket(family, sotype, proto)
20         if err != nil {
21                 return nil, err
22         }
23         if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
24                 poll.CloseFunc(s)
25                 return nil, err
26         }
27         if fd, err = newFD(s, family, sotype, net); err != nil {
28                 poll.CloseFunc(s)
29                 return nil, err
30         }
31
32         // This function makes a network file descriptor for the
33         // following applications:
34         //
35         // - An endpoint holder that opens a passive stream
36         //   connection, known as a stream listener
37         //
38         // - An endpoint holder that opens a destination-unspecific
39         //   datagram connection, known as a datagram listener
40         //
41         // - An endpoint holder that opens an active stream or a
42         //   destination-specific datagram connection, known as a
43         //   dialer
44         //
45         // - An endpoint holder that opens the other connection, such
46         //   as talking to the protocol stack inside the kernel
47         //
48         // For stream and datagram listeners, they will only require
49         // named sockets, so we can assume that it's just a request
50         // from stream or datagram listeners when laddr is not nil but
51         // raddr is nil. Otherwise we assume it's just for dialers or
52         // the other connection holders.
53
54         if laddr != nil && raddr == nil {
55                 switch sotype {
56                 case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
57                         if err := fd.listenStream(ctx, laddr, listenerBacklog(), ctrlCtxFn); err != nil {
58                                 fd.Close()
59                                 return nil, err
60                         }
61                         return fd, nil
62                 case syscall.SOCK_DGRAM:
63                         if err := fd.listenDatagram(ctx, laddr, ctrlCtxFn); err != nil {
64                                 fd.Close()
65                                 return nil, err
66                         }
67                         return fd, nil
68                 }
69         }
70         if err := fd.dial(ctx, laddr, raddr, ctrlCtxFn); err != nil {
71                 fd.Close()
72                 return nil, err
73         }
74         return fd, nil
75 }
76
77 func (fd *netFD) ctrlNetwork() string {
78         switch fd.net {
79         case "unix", "unixgram", "unixpacket":
80                 return fd.net
81         }
82         switch fd.net[len(fd.net)-1] {
83         case '4', '6':
84                 return fd.net
85         }
86         if fd.family == syscall.AF_INET {
87                 return fd.net + "4"
88         }
89         return fd.net + "6"
90 }
91
92 func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
93         var c *rawConn
94         if ctrlCtxFn != nil {
95                 c = newRawConn(fd)
96                 var ctrlAddr string
97                 if raddr != nil {
98                         ctrlAddr = raddr.String()
99                 } else if laddr != nil {
100                         ctrlAddr = laddr.String()
101                 }
102                 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), ctrlAddr, c); err != nil {
103                         return err
104                 }
105         }
106
107         var lsa syscall.Sockaddr
108         var err error
109         if laddr != nil {
110                 if lsa, err = laddr.sockaddr(fd.family); err != nil {
111                         return err
112                 } else if lsa != nil {
113                         if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
114                                 return os.NewSyscallError("bind", err)
115                         }
116                 }
117         }
118         var rsa syscall.Sockaddr  // remote address from the user
119         var crsa syscall.Sockaddr // remote address we actually connected to
120         if raddr != nil {
121                 if rsa, err = raddr.sockaddr(fd.family); err != nil {
122                         return err
123                 }
124                 if crsa, err = fd.connect(ctx, lsa, rsa); err != nil {
125                         return err
126                 }
127                 fd.isConnected = true
128         } else {
129                 if err := fd.init(); err != nil {
130                         return err
131                 }
132         }
133         // Record the local and remote addresses from the actual socket.
134         // Get the local address by calling Getsockname.
135         // For the remote address, use
136         // 1) the one returned by the connect method, if any; or
137         // 2) the one from Getpeername, if it succeeds; or
138         // 3) the one passed to us as the raddr parameter.
139         lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
140         if crsa != nil {
141                 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(crsa))
142         } else if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
143                 fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
144         } else {
145                 fd.setAddr(fd.addrFunc()(lsa), raddr)
146         }
147         return nil
148 }
149
150 func (fd *netFD) listenStream(ctx context.Context, laddr sockaddr, backlog int, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
151         var err error
152         if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
153                 return err
154         }
155         var lsa syscall.Sockaddr
156         if lsa, err = laddr.sockaddr(fd.family); err != nil {
157                 return err
158         }
159
160         if ctrlCtxFn != nil {
161                 c := newRawConn(fd)
162                 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
163                         return err
164                 }
165         }
166
167         if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
168                 return os.NewSyscallError("bind", err)
169         }
170         if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
171                 return os.NewSyscallError("listen", err)
172         }
173         if err = fd.init(); err != nil {
174                 return err
175         }
176         lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
177         fd.setAddr(fd.addrFunc()(lsa), nil)
178         return nil
179 }
180
181 func (fd *netFD) listenDatagram(ctx context.Context, laddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
182         switch addr := laddr.(type) {
183         case *UDPAddr:
184                 // We provide a socket that listens to a wildcard
185                 // address with reusable UDP port when the given laddr
186                 // is an appropriate UDP multicast address prefix.
187                 // This makes it possible for a single UDP listener to
188                 // join multiple different group addresses, for
189                 // multiple UDP listeners that listen on the same UDP
190                 // port to join the same group address.
191                 if addr.IP != nil && addr.IP.IsMulticast() {
192                         if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
193                                 return err
194                         }
195                         addr := *addr
196                         switch fd.family {
197                         case syscall.AF_INET:
198                                 addr.IP = IPv4zero
199                         case syscall.AF_INET6:
200                                 addr.IP = IPv6unspecified
201                         }
202                         laddr = &addr
203                 }
204         }
205         var err error
206         var lsa syscall.Sockaddr
207         if lsa, err = laddr.sockaddr(fd.family); err != nil {
208                 return err
209         }
210
211         if ctrlCtxFn != nil {
212                 c := newRawConn(fd)
213                 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
214                         return err
215                 }
216         }
217         if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
218                 return os.NewSyscallError("bind", err)
219         }
220         if err = fd.init(); err != nil {
221                 return err
222         }
223         lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
224         fd.setAddr(fd.addrFunc()(lsa), nil)
225         return nil
226 }