sock_posix.go 5.86 KB
Newer Older
1
// Copyright 2009 The Go Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Dave Cheney's avatar
Dave Cheney committed
5
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
6

7 8 9
package net

import (
10
	"context"
11
	"internal/poll"
12
	"os"
13
	"syscall"
14 15
)

16 17
// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
// address that can be converted into a syscall.Sockaddr.
18 19
type sockaddr interface {
	Addr
Mikio Hara's avatar
Mikio Hara committed
20 21 22

	// family returns the platform-dependent address family
	// identifier.
23
	family() int
Mikio Hara's avatar
Mikio Hara committed
24 25 26

	// isWildcard reports whether the address is a wildcard
	// address.
27
	isWildcard() bool
Mikio Hara's avatar
Mikio Hara committed
28 29 30 31 32

	// sockaddr returns the address converted into a syscall
	// sockaddr type that implements syscall.Sockaddr
	// interface. It returns a nil interface when the address is
	// nil.
33
	sockaddr(family int) (syscall.Sockaddr, error)
Russ Cox's avatar
Russ Cox committed
34 35 36

	// toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
	toLocal(net string) sockaddr
37 38
}

Mikio Hara's avatar
Mikio Hara committed
39 40
// socket returns a network file descriptor that is ready for
// 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) {
Mikio Hara's avatar
Mikio Hara committed
42
	s, err := sysSocket(family, sotype, proto)
Russ Cox's avatar
Russ Cox committed
43 44
	if err != nil {
		return nil, err
45
	}
Mikio Hara's avatar
Mikio Hara committed
46
	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
47
		poll.CloseFunc(s)
48 49
		return nil, err
	}
Mikio Hara's avatar
Mikio Hara committed
50
	if fd, err = newFD(s, family, sotype, net); err != nil {
51
		poll.CloseFunc(s)
52 53 54
		return nil, err
	}

Mikio Hara's avatar
Mikio Hara committed
55 56 57 58
	// This function makes a network file descriptor for the
	// following applications:
	//
	// - An endpoint holder that opens a passive stream
59
	//   connection, known as a stream listener
Mikio Hara's avatar
Mikio Hara committed
60 61 62 63 64 65 66
	//
	// - An endpoint holder that opens a destination-unspecific
	//   datagram connection, known as a datagram listener
	//
	// - An endpoint holder that opens an active stream or a
	//   destination-specific datagram connection, known as a
	//   dialer
67
	//
Mikio Hara's avatar
Mikio Hara committed
68 69
	// - An endpoint holder that opens the other connection, such
	//   as talking to the protocol stack inside the kernel
70
	//
Mikio Hara's avatar
Mikio Hara committed
71 72 73 74 75
	// For stream and datagram listeners, they will only require
	// named sockets, so we can assume that it's just a request
	// from stream or datagram listeners when laddr is not nil but
	// raddr is nil. Otherwise we assume it's just for dialers or
	// the other connection holders.
76 77

	if laddr != nil && raddr == nil {
Mikio Hara's avatar
Mikio Hara committed
78
		switch sotype {
79
		case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
80
			if err := fd.listenStream(laddr, listenerBacklog); err != nil {
81 82 83 84 85
				fd.Close()
				return nil, err
			}
			return fd, nil
		case syscall.SOCK_DGRAM:
86
			if err := fd.listenDatagram(laddr); err != nil {
87 88 89 90
				fd.Close()
				return nil, err
			}
			return fd, nil
91
		}
92
	}
93
	if err := fd.dial(ctx, laddr, raddr); err != nil {
94 95 96
		fd.Close()
		return nil, err
	}
97 98
	return fd, nil
}
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
	switch fd.family {
	case syscall.AF_INET, syscall.AF_INET6:
		switch fd.sotype {
		case syscall.SOCK_STREAM:
			return sockaddrToTCP
		case syscall.SOCK_DGRAM:
			return sockaddrToUDP
		case syscall.SOCK_RAW:
			return sockaddrToIP
		}
	case syscall.AF_UNIX:
		switch fd.sotype {
		case syscall.SOCK_STREAM:
			return sockaddrToUnix
		case syscall.SOCK_DGRAM:
			return sockaddrToUnixgram
		case syscall.SOCK_SEQPACKET:
			return sockaddrToUnixpacket
		}
	}
	return func(syscall.Sockaddr) Addr { return nil }
}

124
func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
125 126 127 128 129 130
	var err error
	var lsa syscall.Sockaddr
	if laddr != nil {
		if lsa, err = laddr.sockaddr(fd.family); err != nil {
			return err
		} else if lsa != nil {
131
			if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
132 133 134 135
				return os.NewSyscallError("bind", err)
			}
		}
	}
136 137
	var rsa syscall.Sockaddr
	if raddr != nil {
138 139
		if rsa, err = raddr.sockaddr(fd.family); err != nil {
			return err
140
		}
141
		if err := fd.connect(ctx, lsa, rsa); err != nil {
142 143 144 145 146 147
			return err
		}
		fd.isConnected = true
	} else {
		if err := fd.init(); err != nil {
			return err
148 149
		}
	}
150 151
	lsa, _ = syscall.Getsockname(fd.pfd.Sysfd)
	if rsa, _ = syscall.Getpeername(fd.pfd.Sysfd); rsa != nil {
152
		fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa))
153
	} else {
154
		fd.setAddr(fd.addrFunc()(lsa), raddr)
155 156 157
	}
	return nil
}
158

159
func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
160
	if err := setDefaultListenerSockopts(fd.pfd.Sysfd); err != nil {
161 162 163 164 165
		return err
	}
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
166
		if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
167
			return os.NewSyscallError("bind", err)
168
		}
169
	}
170
	if err := listenFunc(fd.pfd.Sysfd, backlog); err != nil {
171 172 173 174 175
		return os.NewSyscallError("listen", err)
	}
	if err := fd.init(); err != nil {
		return err
	}
176
	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
177
	fd.setAddr(fd.addrFunc()(lsa), nil)
178 179
	return nil
}
180

181
func (fd *netFD) listenDatagram(laddr sockaddr) error {
182 183 184 185 186 187 188 189 190 191
	switch addr := laddr.(type) {
	case *UDPAddr:
		// We provide a socket that listens to a wildcard
		// address with reusable UDP port when the given laddr
		// is an appropriate UDP multicast address prefix.
		// This makes it possible for a single UDP listener to
		// join multiple different group addresses, for
		// multiple UDP listeners that listen on the same UDP
		// port to join the same group address.
		if addr.IP != nil && addr.IP.IsMulticast() {
192
			if err := setDefaultMulticastSockopts(fd.pfd.Sysfd); err != nil {
193 194 195 196 197 198 199 200 201 202 203
				return err
			}
			addr := *addr
			switch fd.family {
			case syscall.AF_INET:
				addr.IP = IPv4zero
			case syscall.AF_INET6:
				addr.IP = IPv6unspecified
			}
			laddr = &addr
		}
204
	}
205 206 207
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
208
		if err := syscall.Bind(fd.pfd.Sysfd, lsa); err != nil {
209 210 211
			return os.NewSyscallError("bind", err)
		}
	}
212 213 214
	if err := fd.init(); err != nil {
		return err
	}
215
	lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
216
	fd.setAddr(fd.addrFunc()(lsa), nil)
217
	return nil
218
}