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 }