gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

sockcmsg_unix.go (3286B)


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