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
7package net
8
9import (
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.
18func 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
77func (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
92func (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
150func (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
181func (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}
227