src/pkg/syscall/sockcmsg_unix.go - The Go Programming Language

Golang

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	}