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