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 netbsd openbsd solaris
6
7package unix
8
9import (
10	"runtime"
11	"sync"
12	"syscall"
13	"unsafe"
14)
15
16var (
17	Stdin  = 0
18	Stdout = 1
19	Stderr = 2
20)
21
22const (
23	darwin64Bit    = runtime.GOOS == "darwin" && sizeofPtr == 8
24	dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
25	netbsd32Bit    = runtime.GOOS == "netbsd" && sizeofPtr == 4
26	solaris64Bit   = runtime.GOOS == "solaris" && sizeofPtr == 8
27)
28
29// Do the interface allocations only once for common
30// Errno values.
31var (
32	errEAGAIN error = syscall.EAGAIN
33	errEINVAL error = syscall.EINVAL
34	errENOENT error = syscall.ENOENT
35)
36
37// errnoErr returns common boxed Errno values, to prevent
38// allocations at runtime.
39func errnoErr(e syscall.Errno) error {
40	switch e {
41	case 0:
42		return nil
43	case EAGAIN:
44		return errEAGAIN
45	case EINVAL:
46		return errEINVAL
47	case ENOENT:
48		return errENOENT
49	}
50	return e
51}
52
53// Mmap manager, for use by operating system-specific implementations.
54
55type mmapper struct {
56	sync.Mutex
57	active map[*byte][]byte // active mappings; key is last byte in mapping
58	mmap   func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
59	munmap func(addr uintptr, length uintptr) error
60}
61
62func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
63	if length <= 0 {
64		return nil, EINVAL
65	}
66
67	// Map the requested memory.
68	addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
69	if errno != nil {
70		return nil, errno
71	}
72
73	// Slice memory layout
74	var sl = struct {
75		addr uintptr
76		len  int
77		cap  int
78	}{addr, length, length}
79
80	// Use unsafe to turn sl into a []byte.
81	b := *(*[]byte)(unsafe.Pointer(&sl))
82
83	// Register mapping in m and return it.
84	p := &b[cap(b)-1]
85	m.Lock()
86	defer m.Unlock()
87	m.active[p] = b
88	return b, nil
89}
90
91func (m *mmapper) Munmap(data []byte) (err error) {
92	if len(data) == 0 || len(data) != cap(data) {
93		return EINVAL
94	}
95
96	// Find the base of the mapping.
97	p := &data[cap(data)-1]
98	m.Lock()
99	defer m.Unlock()
100	b := m.active[p]
101	if b == nil || &b[0] != &data[0] {
102		return EINVAL
103	}
104
105	// Unmap the memory and update m.
106	if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
107		return errno
108	}
109	delete(m.active, p)
110	return nil
111}
112
113func Read(fd int, p []byte) (n int, err error) {
114	n, err = read(fd, p)
115	if raceenabled {
116		if n > 0 {
117			raceWriteRange(unsafe.Pointer(&p[0]), n)
118		}
119		if err == nil {
120			raceAcquire(unsafe.Pointer(&ioSync))
121		}
122	}
123	return
124}
125
126func Write(fd int, p []byte) (n int, err error) {
127	if raceenabled {
128		raceReleaseMerge(unsafe.Pointer(&ioSync))
129	}
130	n, err = write(fd, p)
131	if raceenabled && n > 0 {
132		raceReadRange(unsafe.Pointer(&p[0]), n)
133	}
134	return
135}
136
137// For testing: clients can set this flag to force
138// creation of IPv6 sockets to return EAFNOSUPPORT.
139var SocketDisableIPv6 bool
140
141type Sockaddr interface {
142	sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
143}
144
145type SockaddrInet4 struct {
146	Port int
147	Addr [4]byte
148	raw  RawSockaddrInet4
149}
150
151type SockaddrInet6 struct {
152	Port   int
153	ZoneId uint32
154	Addr   [16]byte
155	raw    RawSockaddrInet6
156}
157
158type SockaddrUnix struct {
159	Name string
160	raw  RawSockaddrUnix
161}
162
163func Bind(fd int, sa Sockaddr) (err error) {
164	ptr, n, err := sa.sockaddr()
165	if err != nil {
166		return err
167	}
168	return bind(fd, ptr, n)
169}
170
171func Connect(fd int, sa Sockaddr) (err error) {
172	ptr, n, err := sa.sockaddr()
173	if err != nil {
174		return err
175	}
176	return connect(fd, ptr, n)
177}
178
179func Getpeername(fd int) (sa Sockaddr, err error) {
180	var rsa RawSockaddrAny
181	var len _Socklen = SizeofSockaddrAny
182	if err = getpeername(fd, &rsa, &len); err != nil {
183		return
184	}
185	return anyToSockaddr(&rsa)
186}
187
188func GetsockoptInt(fd, level, opt int) (value int, err error) {
189	var n int32
190	vallen := _Socklen(4)
191	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
192	return int(n), err
193}
194
195func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
196	var rsa RawSockaddrAny
197	var len _Socklen = SizeofSockaddrAny
198	if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
199		return
200	}
201	if rsa.Addr.Family != AF_UNSPEC {
202		from, err = anyToSockaddr(&rsa)
203	}
204	return
205}
206
207func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
208	ptr, n, err := to.sockaddr()
209	if err != nil {
210		return err
211	}
212	return sendto(fd, p, flags, ptr, n)
213}
214
215func SetsockoptByte(fd, level, opt int, value byte) (err error) {
216	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
217}
218
219func SetsockoptInt(fd, level, opt int, value int) (err error) {
220	var n = int32(value)
221	return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
222}
223
224func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
225	return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
226}
227
228func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
229	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
230}
231
232func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
233	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
234}
235
236func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
237	return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
238}
239
240func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
241	return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
242}
243
244func SetsockoptString(fd, level, opt int, s string) (err error) {
245	return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
246}
247
248func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
249	return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
250}
251
252func Socket(domain, typ, proto int) (fd int, err error) {
253	if domain == AF_INET6 && SocketDisableIPv6 {
254		return -1, EAFNOSUPPORT
255	}
256	fd, err = socket(domain, typ, proto)
257	return
258}
259
260func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
261	var fdx [2]int32
262	err = socketpair(domain, typ, proto, &fdx)
263	if err == nil {
264		fd[0] = int(fdx[0])
265		fd[1] = int(fdx[1])
266	}
267	return
268}
269
270func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
271	if raceenabled {
272		raceReleaseMerge(unsafe.Pointer(&ioSync))
273	}
274	return sendfile(outfd, infd, offset, count)
275}
276
277var ioSync int64
278
279func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
280
281func SetNonblock(fd int, nonblocking bool) (err error) {
282	flag, err := fcntl(fd, F_GETFL, 0)
283	if err != nil {
284		return err
285	}
286	if nonblocking {
287		flag |= O_NONBLOCK
288	} else {
289		flag &= ^O_NONBLOCK
290	}
291	_, err = fcntl(fd, F_SETFL, flag)
292	return err
293}
294