src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sockcmsg_unix.go (3214B)


      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 }