1 // Copyright 2011 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 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7 // Socket control messages
16 // Round the length of a raw sockaddr up to align it properly.
17 func cmsgAlignOf(salen
int) int {
18 salign
:= int(sizeofPtr
)
19 // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
20 // Solaris kernels still require 32-bit aligned access to
22 if darwin64Bit || dragonfly64Bit || solaris64Bit
{
25 // NOTE: Solaris always uses 32-bit alignment,
26 // cf. _CMSG_DATA_ALIGNMENT in <sys/socket.h>.
27 if runtime
.GOOS
== "solaris" {
30 return (salen
+ salign
- 1) & ^(salign
- 1)
33 // CmsgLen returns the value to store in the Len field of the Cmsghdr
34 // structure, taking into account any necessary alignment.
35 func CmsgLen(datalen
int) int {
36 return cmsgAlignOf(SizeofCmsghdr
) + datalen
39 // CmsgSpace returns the number of bytes an ancillary element with
40 // payload of the passed data length occupies.
41 func CmsgSpace(datalen
int) int {
42 return cmsgAlignOf(SizeofCmsghdr
) + cmsgAlignOf(datalen
)
45 func cmsgData(h
*Cmsghdr
) unsafe
.Pointer
{
46 return unsafe
.Pointer(uintptr(unsafe
.Pointer(h
)) + uintptr(cmsgAlignOf(SizeofCmsghdr
)))
49 // SocketControlMessage represents a socket control message.
50 type SocketControlMessage
struct {
55 // ParseSocketControlMessage parses b as an array of socket control
57 func ParseSocketControlMessage(b
[]byte) ([]SocketControlMessage
, error
) {
58 var msgs
[]SocketControlMessage
60 for i
+CmsgLen(0) <= len(b
) {
61 h
, dbuf
, err
:= socketControlMessageHeaderAndData(b
[i
:])
65 m
:= SocketControlMessage
{Header
: *h
, Data
: dbuf
}
66 msgs
= append(msgs
, m
)
67 i
+= cmsgAlignOf(int(h
.Len
))
72 func socketControlMessageHeaderAndData(b
[]byte) (*Cmsghdr
, []byte, error
) {
73 h
:= (*Cmsghdr
)(unsafe
.Pointer(&b
[0]))
74 if h
.Len
< SizeofCmsghdr ||
uint64(h
.Len
) > uint64(len(b
)) {
75 return nil, nil, EINVAL
77 return h
, b
[cmsgAlignOf(SizeofCmsghdr
):h
.Len
], nil
80 // UnixRights encodes a set of open file descriptors into a socket
81 // control message for sending to another process.
82 func UnixRights(fds
...int) []byte {
83 datalen
:= len(fds
) * 4
84 b
:= make([]byte, CmsgSpace(datalen
))
85 h
:= (*Cmsghdr
)(unsafe
.Pointer(&b
[0]))
88 h
.SetLen(CmsgLen(datalen
))
90 for _
, fd
:= range fds
{
91 *(*int32)(data
) = int32(fd
)
92 data
= unsafe
.Pointer(uintptr(data
) + 4)
97 // ParseUnixRights decodes a socket control message that contains an
98 // integer array of open file descriptors from another process.
99 func ParseUnixRights(m
*SocketControlMessage
) ([]int, error
) {
100 if m
.Header
.Level
!= SOL_SOCKET
{
103 if m
.Header
.Type
!= SCM_RIGHTS
{
106 fds
:= make([]int, len(m
.Data
)>>2)
107 for i
, j
:= 0, 0; i
< len(m
.Data
); i
+= 4 {
108 fds
[j
] = int(*(*int32)(unsafe
.Pointer(&m
.Data
[i
])))