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// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
6
7package net
8
9import (
10	"context"
11	"internal/poll"
12	"os"
13	"syscall"
14)
15
16// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
17// address that can be converted into a syscall.Sockaddr.
18type sockaddr interface {
19	Addr
20
21	// family returns the platform-dependent address family
22	// identifier.
23	family() int
24
25	// isWildcard reports whether the address is a wildcard
26	// address.
27	isWildcard() bool
28
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)
34
35	// toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
36	toLocal(net string) sockaddr
37}
38
39// socket returns a network file descriptor that is ready for
40// asynchronous I/O using the network poller.
41func 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
45	}
46	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
47		poll.CloseFunc(s)
48		return nil, err
49	}
50	if fd, err = newFD(s, family, sotype, net); err != nil {
51		poll.CloseFunc(s)
52		return nil, err
53	}
54
55	// This function makes a network file descriptor for the
56	// following applications:
57	//
58	// - An endpoint holder that opens a passive stream
59	//   connection, known as a stream listener
60	//
61	// - An endpoint holder that opens a destination-unspecific
62	//   datagram connection, known as a datagram listener
63	//
64	// - An endpoint holder that opens an active stream or a
65	//   destination-specific datagram connection, known as a
66	//   dialer
67	//
68	// - An endpoint holder that opens the other connection, such
69	//   as talking to the protocol stack inside the kernel
70	//
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.
76
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
83			}
84			return fd, nil
85		case syscall.SOCK_DGRAM:
86			if err := fd.listenDatagram(laddr); err != nil {
87				fd.Close()
88				return nil, err
89			}
90			return fd, nil
91		}
92	}
93	if err := fd.dial(ctx, laddr, raddr); err != nil {
94		fd.Close()
95		return nil, err
96	}
97	return fd, nil
98}
99
100func (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
110		}
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
119		}
120	}
121	return func(syscall.Sockaddr) Addr { return nil }
122}
123
124func (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)
133			}
134		}
135	}
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
141		}
142		if crsa, err = fd.connect(ctx, lsa, rsa); err != nil {
143			return err
144		}
145		fd.isConnected = true
146	} else {
147		if err := fd.init(); err != nil {
148			return err
149		}
150	}
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)
164	}
165	return nil
166}
167
168func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
169	if err := setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
170		return err
171	}
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)
177		}
178	}
179	if err := listenFunc(fd.pfd.Sysfd, backlog); err != nil {
180		return os.NewSyscallError("listen", err)
181	}
182	if err := fd.init(); err != nil {
183		return err
184	}
185	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
186	fd.setAddr(fd.addrFunc()(lsa), nil)
187	return nil
188}
189
190func (fd *netFD) listenDatagram(laddr sockaddr) error {
191	switch addr := laddr.(type) {
192	case *UDPAddr:
193		// We provide a socket that listens to a wildcard
194		// address with reusable UDP port when the given laddr
195		// is an appropriate UDP multicast address prefix.
196		// This makes it possible for a single UDP listener to
197		// join multiple different group addresses, for
198		// multiple UDP listeners that listen on the same UDP
199		// port to join the same group address.
200		if addr.IP != nil && addr.IP.IsMulticast() {
201			if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
202				return err
203			}
204			addr := *addr
205			switch fd.family {
206			case syscall.AF_INET:
207				addr.IP = IPv4zero
208			case syscall.AF_INET6:
209				addr.IP = IPv6unspecified
210			}
211			laddr = &addr
212		}
213	}
214	if lsa, err := laddr.sockaddr(fd.family); err != nil {
215		return err
216	} else if lsa != nil {
217		if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
218			return os.NewSyscallError("bind", err)
219		}
220	}
221	if err := fd.init(); err != nil {
222		return err
223	}
224	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
225	fd.setAddr(fd.addrFunc()(lsa), nil)
226	return nil
227}
228