github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/syscall/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 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 // Socket control messages 8 9 package syscall 10 11 import ( 12 "github.com/x04/go/src/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 func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) { 55 h := (*Cmsghdr)(unsafe.Pointer(&b[0])) 56 if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) { 57 return nil, nil, EINVAL 58 } 59 return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil 60 } 61 62 // UnixRights encodes a set of open file descriptors into a socket 63 // control message for sending to another process. 64 func UnixRights(fds ...int) []byte { 65 datalen := len(fds) * 4 66 b := make([]byte, CmsgSpace(datalen)) 67 h := (*Cmsghdr)(unsafe.Pointer(&b[0])) 68 h.Level = SOL_SOCKET 69 h.Type = SCM_RIGHTS 70 h.SetLen(CmsgLen(datalen)) 71 for i, fd := range fds { 72 *(*int32)(h.data(4 * uintptr(i))) = int32(fd) 73 } 74 return b 75 } 76 77 // ParseUnixRights decodes a socket control message that contains an 78 // integer array of open file descriptors from another process. 79 func ParseUnixRights(m *SocketControlMessage) ([]int, error) { 80 if m.Header.Level != SOL_SOCKET { 81 return nil, EINVAL 82 } 83 if m.Header.Type != SCM_RIGHTS { 84 return nil, EINVAL 85 } 86 fds := make([]int, len(m.Data)>>2) 87 for i, j := 0, 0; i < len(m.Data); i += 4 { 88 fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i]))) 89 j++ 90 } 91 return fds, nil 92 }