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 darwin dragonfly freebsd linux netbsd openbsd
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 kernel still requires 32-bit
20 // aligned access to BSD subsystem.
24 // NOTE: Solaris always uses 32-bit alignment,
25 // cf. _CMSG_DATA_ALIGNMENT in <sys/socket.h>.
26 if runtime
.GOOS
== "solaris" {
29 return (salen
+ salign
- 1) & ^(salign
- 1)
32 // CmsgLen returns the value to store in the Len field of the Cmsghdr
33 // structure, taking into account any necessary alignment.
34 func CmsgLen(datalen
int) int {
35 return cmsgAlignOf(SizeofCmsghdr
) + datalen
38 // CmsgSpace returns the number of bytes an ancillary element with
39 // payload of the passed data length occupies.
40 func CmsgSpace(datalen
int) int {
41 return cmsgAlignOf(SizeofCmsghdr
) + cmsgAlignOf(datalen
)
44 func cmsgData(h
*Cmsghdr
) unsafe
.Pointer
{
45 return unsafe
.Pointer(uintptr(unsafe
.Pointer(h
)) + uintptr(cmsgAlignOf(SizeofCmsghdr
)))
48 // SocketControlMessage represents a socket control message.
49 type SocketControlMessage
struct {
54 // ParseSocketControlMessage parses b as an array of socket control
56 func ParseSocketControlMessage(b
[]byte) ([]SocketControlMessage
, error
) {
57 var msgs
[]SocketControlMessage
59 for i
+CmsgLen(0) <= len(b
) {
60 h
, dbuf
, err
:= socketControlMessageHeaderAndData(b
[i
:])
64 m
:= SocketControlMessage
{Header
: *h
, Data
: dbuf
}
65 msgs
= append(msgs
, m
)
66 i
+= cmsgAlignOf(int(h
.Len
))
71 func socketControlMessageHeaderAndData(b
[]byte) (*Cmsghdr
, []byte, error
) {
72 h
:= (*Cmsghdr
)(unsafe
.Pointer(&b
[0]))
73 if h
.Len
< SizeofCmsghdr ||
int(h
.Len
) > len(b
) {
74 return nil, nil, EINVAL
76 return h
, b
[cmsgAlignOf(SizeofCmsghdr
):h
.Len
], nil
79 // UnixRights encodes a set of open file descriptors into a socket
80 // control message for sending to another process.
81 func UnixRights(fds
...int) []byte {
82 datalen
:= len(fds
) * 4
83 b
:= make([]byte, CmsgSpace(datalen
))
84 h
:= (*Cmsghdr
)(unsafe
.Pointer(&b
[0]))
87 h
.SetLen(CmsgLen(datalen
))
88 data
:= uintptr(cmsgData(h
))
89 for _
, fd
:= range fds
{
90 *(*int32)(unsafe
.Pointer(data
)) = int32(fd
)
96 // ParseUnixRights decodes a socket control message that contains an
97 // integer array of open file descriptors from another process.
98 func ParseUnixRights(m
*SocketControlMessage
) ([]int, error
) {
99 if m
.Header
.Level
!= SOL_SOCKET
{
102 if m
.Header
.Type
!= SCM_RIGHTS
{
105 fds
:= make([]int, len(m
.Data
)>>2)
106 for i
, j
:= 0, 0; i
< len(m
.Data
); i
+= 4 {
107 fds
[j
] = int(*(*int32)(unsafe
.Pointer(&m
.Data
[i
])))