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