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 //go:build unix || windows
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)
23 if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
27 if fd, err = newFD(s, family, sotype, net); err != nil {
32 // This function makes a network file descriptor for the
33 // following applications:
35 // - An endpoint holder that opens a passive stream
36 // connection, known as a stream listener
38 // - An endpoint holder that opens a destination-unspecific
39 // datagram connection, known as a datagram listener
41 // - An endpoint holder that opens an active stream or a
42 // destination-specific datagram connection, known as a
45 // - An endpoint holder that opens the other connection, such
46 // as talking to the protocol stack inside the kernel
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.
54 if laddr != nil && raddr == nil {
56 case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
57 if err := fd.listenStream(ctx, laddr, listenerBacklog(), ctrlCtxFn); err != nil {
62 case syscall.SOCK_DGRAM:
63 if err := fd.listenDatagram(ctx, laddr, ctrlCtxFn); err != nil {
70 if err := fd.dial(ctx, laddr, raddr, ctrlCtxFn); err != nil {
77 func (fd *netFD) ctrlNetwork() string {
79 case "unix", "unixgram", "unixpacket":
82 switch fd.net[len(fd.net)-1] {
86 if fd.family == syscall.AF_INET {
92 func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
98 ctrlAddr = raddr.String()
99 } else if laddr != nil {
100 ctrlAddr = laddr.String()
102 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), ctrlAddr, c); err != nil {
107 var lsa syscall.Sockaddr
110 if lsa, err = laddr.sockaddr(fd.family); err != nil {
112 } else if lsa != nil {
113 if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
114 return os.NewSyscallError("bind", err)
118 var rsa syscall.Sockaddr // remote address from the user
119 var crsa syscall.Sockaddr // remote address we actually connected to
121 if rsa, err = raddr.sockaddr(fd.family); err != nil {
124 if crsa, err = fd.connect(ctx, lsa, rsa); err != nil {
127 fd.isConnected = true
129 if err := fd.init(); err != nil {
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)
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))
145 fd.setAddr(fd.addrFunc()(lsa), raddr)
150 func (fd *netFD) listenStream(ctx context.Context, laddr sockaddr, backlog int, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) error {
152 if err = setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
155 var lsa syscall.Sockaddr
156 if lsa, err = laddr.sockaddr(fd.family); err != nil {
160 if ctrlCtxFn != nil {
162 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
167 if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
168 return os.NewSyscallError("bind", err)
170 if err = listenFunc(fd.pfd.Sysfd, backlog); err != nil {
171 return os.NewSyscallError("listen", err)
173 if err = fd.init(); err != nil {
176 lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
177 fd.setAddr(fd.addrFunc()(lsa), nil)
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) {
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 {
197 case syscall.AF_INET:
199 case syscall.AF_INET6:
200 addr.IP = IPv6unspecified
206 var lsa syscall.Sockaddr
207 if lsa, err = laddr.sockaddr(fd.family); err != nil {
211 if ctrlCtxFn != nil {
213 if err := ctrlCtxFn(ctx, fd.ctrlNetwork(), laddr.String(), c); err != nil {
217 if err = syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
218 return os.NewSyscallError("bind", err)
220 if err = fd.init(); err != nil {
223 lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
224 fd.setAddr(fd.addrFunc()(lsa), nil)