Source file src/pkg/syscall/sockcmsg_unix.go
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.
4
5 // +build darwin freebsd linux netbsd openbsd
6
7 // Socket control messages
8
9 package syscall
10
11 import (
12 "unsafe"
13 )
14
15 // Round the length of a raw sockaddr up to align it propery.
16 func cmsgAlignOf(salen int) int {
17 salign := sizeofPtr
18 // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
19 // aligned access to BSD subsystem.
20 if darwinAMD64 {
21 salign = 4
22 }
23 if salen == 0 {
24 return salign
25 }
26 return (salen + salign - 1) & ^(salign - 1)
27 }
28
29 // CmsgLen returns the value to store in the Len field of the Cmsghdr
30 // structure, taking into account any necessary alignment.
31 func CmsgLen(datalen int) int {
32 return cmsgAlignOf(SizeofCmsghdr) + datalen
33 }
34
35 // CmsgSpace returns the number of bytes an ancillary element with
36 // payload of the passed data length occupies.
37 func CmsgSpace(datalen int) int {
38 return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
39 }
40
41 func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
42 return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
43 }
44
45 type SocketControlMessage struct {
46 Header Cmsghdr
47 Data []byte
48 }
49
50 func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
51 var (
52 h *Cmsghdr
53 dbuf []byte
54 e error
55 cmsgs []SocketControlMessage
56 )
57
58 for len(buf) >= CmsgLen(0) {
59 h, dbuf, e = socketControlMessageHeaderAndData(buf)
60 if e != nil {
61 break
62 }
63 m := SocketControlMessage{}
64 m.Header = *h
65 m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
66 cmsgs = append(cmsgs, m)
67 buf = buf[cmsgAlignOf(int(h.Len)):]
68 }
69
70 return cmsgs, e
71 }
72
73 func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
74 h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
75 if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
76 return nil, nil, EINVAL
77 }
78 return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
79 }
80
81 // UnixRights encodes a set of open file descriptors into a socket
82 // control message for sending to another process.
83 func UnixRights(fds ...int) []byte {
84 datalen := len(fds) * 4
85 buf := make([]byte, CmsgSpace(datalen))
86 cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
87 cmsg.Level = SOL_SOCKET
88 cmsg.Type = SCM_RIGHTS
89 cmsg.SetLen(CmsgLen(datalen))
90
91 data := uintptr(cmsgData(cmsg))
92 for _, fd := range fds {
93 *(*int32)(unsafe.Pointer(data)) = int32(fd)
94 data += 4
95 }
96
97 return buf
98 }
99
100 // ParseUnixRights decodes a socket control message that contains an
101 // integer array of open file descriptors from another process.
102 func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
103 if msg.Header.Level != SOL_SOCKET {
104 return nil, EINVAL
105 }
106 if msg.Header.Type != SCM_RIGHTS {
107 return nil, EINVAL
108 }
109 fds := make([]int, len(msg.Data)>>2)
110 for i, j := 0, 0; i < len(msg.Data); i += 4 {
111 fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
112 j++
113 }
114 return fds, nil
115 }