golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/sockcmsg_unix.go (about) 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 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos 6 7 // Socket control messages 8 9 package unix 10 11 import ( 12 "unsafe" 13 ) 14 15 // CmsgLen returns the value to store in the Len field of the Cmsghdr 16 // structure, taking into account any necessary alignment. 17 func CmsgLen(datalen int) int { 18 return cmsgAlignOf(SizeofCmsghdr) + datalen 19 } 20 21 // CmsgSpace returns the number of bytes an ancillary element with 22 // payload of the passed data length occupies. 23 func CmsgSpace(datalen int) int { 24 return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen) 25 } 26 27 func (h *Cmsghdr) data(offset uintptr) unsafe.Pointer { 28 return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)) + offset) 29 } 30 31 // SocketControlMessage represents a socket control message. 32 type SocketControlMessage struct { 33 Header Cmsghdr 34 Data []byte 35 } 36 37 // ParseSocketControlMessage parses b as an array of socket control 38 // messages. 39 func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) { 40 var msgs []SocketControlMessage 41 i := 0 42 for i+CmsgLen(0) <= len(b) { 43 h, dbuf, err := socketControlMessageHeaderAndData(b[i:]) 44 if err != nil { 45 return nil, err 46 } 47 m := SocketControlMessage{Header: *h, Data: dbuf} 48 msgs = append(msgs, m) 49 i += cmsgAlignOf(int(h.Len)) 50 } 51 return msgs, nil 52 } 53 54 // ParseOneSocketControlMessage parses a single socket control message from b, returning the message header, 55 // message data (a slice of b), and the remainder of b after that single message. 56 // When there are no remaining messages, len(remainder) == 0. 57 func ParseOneSocketControlMessage(b []byte) (hdr Cmsghdr, data []byte, remainder []byte, err error) { 58 h, dbuf, err := socketControlMessageHeaderAndData(b) 59 if err != nil { 60 return Cmsghdr{}, nil, nil, err 61 } 62 if i := cmsgAlignOf(int(h.Len)); i < len(b) { 63 remainder = b[i:] 64 } 65 return *h, dbuf, remainder, nil 66 } 67 68 func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) { 69 h := (*Cmsghdr)(unsafe.Pointer(&b[0])) 70 if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) { 71 return nil, nil, EINVAL 72 } 73 return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil 74 } 75 76 // UnixRights encodes a set of open file descriptors into a socket 77 // control message for sending to another process. 78 func UnixRights(fds ...int) []byte { 79 datalen := len(fds) * 4 80 b := make([]byte, CmsgSpace(datalen)) 81 h := (*Cmsghdr)(unsafe.Pointer(&b[0])) 82 h.Level = SOL_SOCKET 83 h.Type = SCM_RIGHTS 84 h.SetLen(CmsgLen(datalen)) 85 for i, fd := range fds { 86 *(*int32)(h.data(4 * uintptr(i))) = int32(fd) 87 } 88 return b 89 } 90 91 // ParseUnixRights decodes a socket control message that contains an 92 // integer array of open file descriptors from another process. 93 func ParseUnixRights(m *SocketControlMessage) ([]int, error) { 94 if m.Header.Level != SOL_SOCKET { 95 return nil, EINVAL 96 } 97 if m.Header.Type != SCM_RIGHTS { 98 return nil, EINVAL 99 } 100 fds := make([]int, len(m.Data)>>2) 101 for i, j := 0, 0; i < len(m.Data); i += 4 { 102 fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i]))) 103 j++ 104 } 105 return fds, nil 106 }